poj 1149 PIGS

来源:互联网 发布:zanti网络渗透工具 编辑:程序博客网 时间:2024/06/07 01:26

http://poj.org/problem?id=1149

纠结了很久才会做的最大流。

按照朴素的思想我们可以建立如下的图:

假设在某一轮交易中i号猪圈被打开,那么在下一次有人可以打开i号猪圈的时候,我们只需将这两个人之间建立一条流量为无穷的边即可。还有一点是, 在一条路径S到达人的路径中,流量为无穷的边可以直接删除,因为相当于不需要一个中转站,两个节点可以直接相连。这样的话我们只需要保留S(0),猪圈(1, m),人(m+1, m+n),T(m+n+1)这些点来建图。经过此番简化就可以建图辣!

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;const int INF = 1e9;int Q[2500],h,t;int level[2500],S,T;int head[2500], cnt;int c[2500],pre[2500];struct edge{int v,c,next;}node[250000];void Init(){cnt = 0;memset(head, -1, sizeof(head));}void addedge(int u, int v, int c){//cout << u << " " << v << " " << c << endl;node[cnt].v = v;node[cnt].c = c;node[cnt].next = head[u];head[u] = cnt++;}bool BFS(){//构建层次图memset(level, -1, sizeof(level));level[S] = 0, h = 0, t = 1, Q[1] = S;while(h < t){int u = Q[++h];for(int i=head[u]; i!=-1; i=node[i].next){int v = node[i].v;if(node[i].c > 0 && level[v] == -1){level[v] = level[u] + 1;Q[++t] = v;if(v == T) return true;}}}return false;}int DINIC(int id, int minflow){//返回增广路的瓶颈流量if(id == T) return minflow;int a = 0;for(int i=head[id]; i!=-1; i=node[i].next){int v = node[i].v;if(node[i].c > 0 && level[v] == level[id] + 1&& (a = DINIC(v, min(minflow, node[i].c)))){node[i].c -= a;node[i^1].c += a;return a;}}return 0;}int main(){int m,n;while(scanf("%d%d",&m,&n) == 2){Init();        S = 0, T = m+n+1;for(int i=1; i<=m; i++){//源点到猪圈的边scanf("%d",&c[i]);addedge(S, i, c[i]);addedge(i, S, 0);}for(int i=1; i<=m; i++) pre[i] = i;for(int i=1; i<=n; i++){int a,b;scanf("%d",&a);for(int j=1; j<=a; j++){//将猪圈与猪圈间的边转化为人与人之间的边int u;scanf("%d",&u);addedge(pre[u], m+i, INF);addedge(m+i, pre[u], 0);pre[u] = m+i;}scanf("%d",&b);addedge(m+i, m+n+1, b);//人与汇点之间的边addedge(m+n+1, m+i, 0);}int tmp, ans = 0;while(BFS()){while(tmp = DINIC(S, INF)) ans += tmp;}printf("%d\n",ans);}return 0;}



0 0
原创粉丝点击