hdoj 3996 Gold Mine 【最小割 之 最大权闭合图】

来源:互联网 发布:读取二维码扫码枪数据 编辑:程序博客网 时间:2024/05/21 15:51



Gold Mine

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2415    Accepted Submission(s): 525


Problem Description
Long long ago, there is a gold mine.The mine consist of many layout, so some area is easy to dig, but some is very hard to dig.To dig one gold, we should cost some value and then gain some value. There are many area that have gold, because of the layout, if one people want to dig one gold in some layout, he must dig some gold on some layout that above this gold's layout. A gold seeker come here to dig gold.The question is how much value the gold he can dig, suppose he have infinite money in the begin.
 

Input
First line the case number.(<=10)

Then for every case:
  one line for layout number.(<=100)
  for every layout
  first line gold number(<=25)
  then one line for the dig cost and the gold value(32bit integer), the related gold number that must be digged first(<=50)

then w lines descripte the related gold followed, each line two number, one layout num, one for the order in that layout
see sample for details
 

Output
Case #x: y.
x for case number, count from 1.
y for the answer.
 

Sample Input
12110 100 0210 100 11 110 100 11 1
 

Sample Output
Case #1: 270
 



题意:有一座矿山,矿山里面有N个待开发的地方,每个地方都会有一定数目的金矿,开采一个金矿会花费一定数目的金币,相应的也会有一定的收益。但是对于每个金矿,在开采它之前,必须要先开采与它有联系的所有金矿。假设初始拥有的费用是无穷大的,现在问你能获得的最大收益。



思路:明显的最大权闭合图,找出依赖关系,建好图,直接就是最小割了。


建图:设置超级源点source,超级汇点sink

1,source向所有正收益的金矿建边,容量为正收益;

2,所有负收益的金矿向sink建边,容量为负收益;

3,依赖关系a -> b(必须先开采b再开采a)建边,容量为无穷大。

记录所有正收益之和sum,答案就是sum - 最小割。



注意:会超int型,还有无穷大的值要设大点。


AC代码:最后结果题目给出的数据,不会有负数,所以直接输出答案也是可以的。


#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define MAXN 3000#define MAXM 500000#define INF 0x3f3f3f3f3f#define LL long longusing namespace std;struct Edge{    int from, to;    LL cap, flow;;    int next;};Edge edge[MAXM];int head[MAXN], edgenum;int dist[MAXN], cur[MAXN];bool vis[MAXN];int N;void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, LL w){    Edge E1 = {u, v, w, 0, head[u]};    edge[edgenum] = E1;    head[u] = edgenum++;    Edge E2 = {v, u, 0, 0, head[v]};    edge[edgenum] = E2;    head[v] = edgenum++;}LL sum;//记录图中所有正权点 的权值之和int source, sink;struct Node{    LL c, g;    int w, layout[60], order[60];};Node rec[110][30];//记录第i个layout的第j个gold的信息int num[110];//记录第i个layout里面有多少个goldint have[110];//记录第i个layout前面有多少个goldvoid getMap(){    sum = 0;    int t = 0;    for(int i = 1; i <= N; i++)    {        have[i] = t;        scanf("%d", &num[i]);        t += num[i];        for(int j = 1; j <= num[i]; j++)        {            scanf("%lld%lld%d", &rec[i][j].c, &rec[i][j].g, &rec[i][j].w);            for(int k = 0; k < rec[i][j].w; k++)                scanf("%d%d", &rec[i][j].layout[k], &rec[i][j].order[k]);        }    }    source = 0, sink = t+1;    for(int i = 1; i <= N; i++)    {        for(int j = 1; j <= num[i]; j++)        {            int u = have[i] + j;            if(rec[i][j].g - rec[i][j].c > 0)                addEdge(source, u, rec[i][j].g - rec[i][j].c), sum += rec[i][j].g - rec[i][j].c;            else                addEdge(u, sink, -rec[i][j].g + rec[i][j].c);            for(int k = 0; k < rec[i][j].w; k++)//依赖关系建边            {                int v = have[rec[i][j].layout[k]] + rec[i][j].order[k];                addEdge(u, v, INF);            }        }    }}bool BFS(int s, int t){    queue<int> Q;    memset(dist, -1, sizeof(dist));    memset(vis, false, sizeof(vis));    dist[s] = 0;    vis[s] = true;    Q.push(s);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(!vis[E.to] && E.cap > E.flow)            {                dist[E.to] = dist[u] + 1;                if(E.to == t) return true;                vis[E.to] = true;                Q.push(E.to);            }        }    }    return false;}LL DFS(int x, LL a, int t){    if(x == t || a == 0) return a;    LL flow = 0, f;    for(int &i = cur[x]; i != -1; i = edge[i].next)    {        Edge &E = edge[i];        if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0)        {            edge[i].flow += f;            edge[i^1].flow -= f;            flow += f;            a -= f;            if(a == 0) break;        }    }    return flow;}LL Maxflow(int s, int t){    LL flow = 0;    while(BFS(s, t))    {        memcpy(cur, head, sizeof(head));        flow += DFS(s, INF, t);    }    return flow;}int main(){    int t, k = 1;    scanf("%d", &t);    while(t--)    {        scanf("%d", &N);        init();        getMap();        LL ans = sum - Maxflow(source, sink);        printf("Case #%d: %lld\n", k++, ans > 0 ? ans : 0);    }    return 0;}


0 0