ZOJ 3229 有上下界最大流
时间:2014-05-08 22:39:11
收藏:0
阅读:412
1: /**
2: ZOJ 3229 有上下界的最大流
3: 两次求最大流的过程,非二分
4: 有源汇上下界的最大流问题, 首先连接 sink -> src, [0,INF].
5: 根据net的正负,来建立 Supersrc 与 supersink 之间的边,做一次 maxflow.
6: 若所有的Supersrc 与 Supersink满流,则说明存在可行流.
7: 然后删除 sink -> src之间的边.(cap 置零即可). 从src -> sink 做一次最大流.
8: 两次最大流的和即为整个网络的最大流.
9: */
10: 11: #include<iostream> 12: #include<cmath> 13: #include<memory>14: #include <string.h>
15: #include <cstdio> 16: #include <vector>17: using namespace std;
18: 19: #define V 1500 // vertex
20: #define E V *80 // edge
21: #define INF 0x3F3F3F3F // 1061109567
22: 23: int i,j,k;
24: #define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
25: #define snuke(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
26: 27: struct MaxFlow
28: {29: struct Edge
30: {31: int v, w, next; //w for capicity
32: int lb,up;
33: } edge[E]; 34: 35: int head[V]; // head[u]表示顶点u第一条邻接边的序号, 若head[u] = -1, u没有邻接边
36: int e; // the index of the edge
37: int src, sink;
38: int net[V]; // 流入此节点的流的下界和 - 流出此节点的流的下界和,对于带上下界的来进行使用
39: 40: 41: void addedge(int u, int v, int w, int lb = 0, int up = INF, int rw = 0)
42: { 43: edge[e].v = v; 44: edge[e].w= w; 45: edge[e].next = head[u]; 46: edge[e].lb = lb, edge[e].up = up; 47: head[u] = e++;48: // reverse edge v -> u
49: edge[e].v = u; 50: edge[e].w = rw; 51: edge[e].lb = lb, edge[e].up = up; 52: edge[e].next = head[v]; 53: head[v] = e++; 54: } 55: 56: int ISAP(int VertexNum )
57: {58: int u, v, max_flow, aug, min_lev;
59: int curedge[V], parent[V], level[V];
60: int count[V], augment[V];
61: 62: memset(level, 0, sizeof(level));
63: memset(count, 0, sizeof(count));
64: REP(i,VertexNum+1) curedge[i] = head[i]; 65: max_flow = 0; 66: augment[src] = INF; 67: parent[src] = -1; 68: u = src; 69: 70: while (level[src] < VertexNum)
71: {72: if (u == sink)
73: { 74: max_flow += augment[sink]; 75: aug = augment[sink];76: for (v = parent[sink]; v != -1; v = parent[v])
77: { 78: i = curedge[v]; 79: edge[i].w -= aug; 80: edge[i^1].w += aug; 81: augment[edge[i].v] -= aug;82: if (edge[i].w == 0) u = v;
83: } 84: }85: for (i = curedge[u]; i != -1; i = edge[i].next)
86: { 87: v = edge[i].v;88: if (edge[i].w > 0 && level[u] == (level[v]+1))
89: { 90: augment[v] = min(augment[u], edge[i].w); 91: curedge[u] = i; 92: parent[v] = u; 93: u = v;94: break;
95: } 96: }97: if (i == -1)
98: {99: if (--count[level[u]] == 0) break;
100: curedge[u] = head[u]; 101: min_lev = VertexNum;102: for (i = head[u]; i != -1; i = edge[i].next)
103: if (edge[i].w > 0)
104: min_lev = min(level[edge[i].v], min_lev); 105: level[u] = min_lev + 1; 106: count[level[u]]++;107: if (u != src ) u = parent[u];
108: } 109: }110: return max_flow;
111: }112: // girl 0-m-1, day m,m+n-1, src m+n, sink m+n+1. all m+n+2 point
113: void solve()
114: {115: int N,M; // n days m girl
116: while(scanf("%d%d", &N,&M) != EOF)
117: { 118: e = 0;119: memset(head, -1, sizeof(head));
120: memset(net, 0, sizeof(net));
121: int G; src = M+N, sink = M+N+1;
122: for(int i=0; i<M; i++)
123: {124: scanf("%d", &G);
125: addedge(i,sink,INF-G, G,INF); 126: net[i] -= G; 127: net[sink] += G; 128: }129: vector<int> CE;
130: for(int i=0; i<N; i++)
131: {132: int C,D; scanf("%d%d", &C,&D);
133: addedge(src, M+i, D, 0, D);134: for(int j=0; j<C; j++)
135: {136: int T,L,R; scanf("%d%d%d", &T,&L,&R);
137: CE.push_back(e); 138: addedge(M+i,T,R-L, L,R); 139: net[M+i] -= L; 140: net[T] += L; 141: } 142: }143: int spec = e;
144: // 添加从sink -> src 容量为INF的边
145: addedge(sink, src, INF,0,INF);146: src = M+N+2; sink = M+N+3; // M+N+4 point
147: int rangea = e;
148: for(int i=0; i<M+N+2; i++)
149: {150: if(net[i] >= 0) addedge(src, i, net[i]);
151: else addedge(i, sink,-net[i]);
152: }153: double ret = 0;
154: int rangeb = e;
155: // 从super src ->super sink 做一次最大流
156: ret+=ISAP(M+N+4);157: bool flag = true;
158: // 判断是否满流
159: for(int i= rangea; i<rangeb; i+=2)
160: {161: if(edge[i].w !=0)
162: {163: flag = false;
164: break;
165: } 166: }167: if(flag)
168: {169: // 修改 src sink,然后把 从sink -> src 的边删除
170: src = M+N; sink = M+N+1; 171: edge[spec].w = 0; edge[spec+1].w = 0;172: // 从 src->sink 做一次最大流
173: ret += ISAP(M+N+2);174: int tmp = ret;
175: printf("%d\n", tmp);
176: for(int i=0; i<CE.size(); i++)
177: printf("%d\n", edge[CE[i]+1].lb + edge[CE[i]+1].w);
178: }else printf("-1\n");
179: cout<<endl; 180: } 181: } 182: }sap; 183: 184: int main()
185: {186: // freopen("1.txt","r",stdin);
187: sap.solve();188: return 0;
189: }
评论(0)