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

来源:互联网 发布:游戏数据加密算法 编辑:程序博客网 时间:2024/06/05 15:56


题意:有一个技能树,每个技能有一些“先修技能”,先修技能都得到后才可以得到当前技能。三种方法: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;}


原创粉丝点击