您的位置:首页 > 其它

UVALive 7264 Kejin Game (最大流最小割)

2017-07-23 21:06 811 查看
题意:有一个技能树,每个技能有一些“先修技能”,先修技能都得到后才可以得到当前技能。三种方法:1.逐个修技能,花费是技能的点值(数据中的倒数第二行)2.花费一些钱去掉某些边 (边权就是先修的条件)  3.跳过之前的条件直接得到某个技能,求得到某技能的最小花费

思路:经典建图。。建完图你会发现最小割就是要求的答案...

 将每个点拆成 i 和 i',设一个源点与汇点。

1.对于边i--->j,连边i'--->j,容量为对应边的费用。

2.源点到 i 连边,容量为满足条件后购买 i 的费用。

3.对于 i 和 i' 连边,容量为直接购买 i 的费用。

4.对于目标点向汇点连边,容量为INF。

因为图中每个割为一种获得目标技能的方案,所以求最小割即可。

一开始知道最小割不就是一个原来联通图,通过去掉一些权值最小边, 变为不联通的图,这题怎么想也想不董根最小割啥关系啊,画了图知道了,这题是通过建边来将答案变成最小割(字比较难看QAQ



你会发现, 1234个割, 每个其实都是一种答案, 2把e点跟他相邻的三个技能点都取消了, 说明他没有前置技能点了,只需要加上平常的花费就好了, 1很简单, 就是从1到e挨个修炼,3,其实是把E的前置技能点全部买断了,再加上到E的花费, 4就是直接把E买断了...将E到t负值INF, 也就是最小割只能在前面的边出现...

总结下:

这题建图方式很强, 通过建图, 将问题转化为最小割问题,这也提示我们, 当有前置条件, 求最大最小的时候, 可能是网络流, 可能要转化成最小割, 这种建图方式要学一下,每个技能都直接练到源点, 单个技能肯定要拆点将它变成一个流, 这题,也许能出是通过画图看出来的, 以后不知道怎么建图,尝试画图,先把一些常规的画出来,往最小割拼拼....

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e3+5;
const int maxv = 1e5 + 5;
int head[maxn], cur[maxn], d[maxn], s, t, k, sum;
int n, m, g;
struct node
{
int v, w, next;
}edge[maxv];
void addEdge(int u, int v, int w)
{
edge[k].v = v;
edge[k].w = w;
edge[k].next = head[u];
head[u] = k++;
edge[k].v = u;
edge[k].w = 0;
edge[k].next = head[v];
head[v] = k++;

}
int bfs()
{
memset(d, 0, sizeof(d));
d[s] = 1;
queue<int> q;
q.push(s);
while(!q.empty())
{
int u = q.front();
if(u == t) return 1;
q.pop();
for(int i = head[u]; i != -1; i = edge[i].next)
{
int to = edge[i].v, w = edge[i].w;
if(w && d[to] == 0)
{
d[to] = d[u] + 1;
if(to == t) return 1;
q.push(to);
}
}
}
return 0;
}
int dfs(int u, int maxflow)
{
if(u == t) return maxflow;
int ret = 0;
for(int i = cur[u]; i != -1; i = edge[i].next)
{
int to = edge[i].v, w = edge[i].w;
if(w && d[to] == d[u]+1)
{
int f = dfs(to, min(maxflow-ret, w));
edge[i].w -= f;
edge[i^1].w += f;
ret += f;
if(ret == maxflow) return ret;
}
}
return ret;
}
int Dinic()
{
int ans = 0;
while(bfs() == 1)
{
memcpy(cur, head, sizeof(head));
ans += dfs(s, INF);
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d%d", &n, &m, &g);
s = 0, t = n*2+1, k = 0;
memset(head, -1, sizeof(head));
int x, y, z;
for(int i = 1; i <= m; i++)
{
scanf("%d%d%d", &x, &y, &z);
addEdge(n+x, y, z);
}
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
addEdge(s, i, x);
}
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
addEdge(i, i+n, x);
}
addEdge(g+n, t, INF);
printf("%d\n", Dinic());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: