【网络流之最大权闭包专题】解题报告
最大权闭包模型中源点与正收益的点连边,负收益的点与汇点连边,容量取绝对值,然后相关联的点之间之间连容量为无穷大的边。
具体可参见胡伯涛:《最小割模型在信息学竞赛中的应用》
HDU 3061 Battle
应该是最裸的最大权闭包题了。
1 #include <vector> 2 #include <list> 3 #include <map> 4 #include <set> 5 #include <queue> 6 #include <deque> 7 #include <stack> 8 #include <algorithm> 9 #include <sstream> 10 #include <iostream> 11 #include <iomanip> 12 #include <cstdio> 13 #include <cstdlib> 14 #include <cstring> 15 #include <cmath> 16 #include <queue> 17 using namespace std; 18 #define pii pair<LL,LL> 19 #define clr(a) memset((a),0,sizeof (a)) 20 #define rep(i,a,b) for(LL i=(a);i<=(LL)(b);i++) 21 #define per(i,a,b) for(LL i=(a);i>=(LL)(b);i--) 22 #define oo ((LL)2000000007)*((LL)2000000007) 23 #define eps 1e-6 24 #define MAXN 1005 25 #define MAXM 200005 26 #define MOD 1000000007 27 #define debug puts("reach here") 28 #define MP make_pair 29 #define PB push_back 30 #define RI(x) scanf("%I64d",&x) 31 #define RII(x,y) scanf("%I64d%I64d",&x,&y) 32 #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) 33 typedef long long LL; 34 35 struct Edge 36 { 37 int u, v, next; 38 LL w; 39 }E[MAXM]; 40 41 int gap[MAXN], pre[MAXN], cur[MAXN], dis[MAXN]; 42 LL n, m; 43 LL N; 44 int head[MAXN], NE; 45 bool vis[MAXN]; 46 47 void add_edge (int u, int v, LL w) 48 { 49 E[NE].u = u; E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; 50 E[NE].u = v; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; 51 } 52 53 inline void checkmin(LL &a,LL b) {if(a == -1 || a > b)a = b;} 54 55 LL sap(int s, int t) 56 { 57 clr(dis); clr(gap); 58 for(int i=0;i<N;++i) cur[i]=head[i]; 59 int u=pre[s]=s; 60 LL maxflow=0; 61 LL aug=-1; 62 gap[0]=N; 63 while(dis[s]<N) 64 { 65 loop:for(int &i=cur[u];i!=-1;i=E[i].next) 66 { 67 LL v=E[i].v; 68 if(E[i].w && dis[u]==dis[v]+1) 69 { 70 checkmin(aug,E[i].w); 71 pre[v]=u; 72 u=v; 73 if(v==t) 74 { 75 maxflow += aug; 76 for(u=pre[u];v!=s;v=u,u=pre[u]) 77 { 78 E[cur[u]].w-=aug; 79 E[cur[u]^1].w+=aug; 80 } 81 aug=-1; 82 } 83 goto loop; 84 } 85 } 86 int mindis=N; 87 for(int i=head[u];i!=-1;i=E[i].next) 88 { 89 int v=E[i].v; 90 if(E[i].w && mindis>dis[v]) 91 { 92 cur[u]=i; 93 mindis=dis[v]; 94 } 95 } 96 if((--gap[dis[u]])==0) break; 97 gap[dis[u]=mindis+1]++; 98 u=pre[u]; 99 } 100 return maxflow; 101 } 102 103 void init() 104 { 105 NE = 0; 106 memset(head, -1, sizeof head); 107 } 108 109 int main() 110 { 111 int a, b; 112 LL sum, v; 113 while(RII(n, m) != EOF) 114 { 115 init(); 116 LL s = 0, t = n + 1; 117 sum = 0; 118 N = t + 1; 119 rep(i,1,n) 120 { 121 RI(v); 122 if(v > 0) 123 { 124 add_edge(s, i, v); 125 sum += v; 126 } 127 else 128 add_edge(i, t, -v); 129 } 130 rep(i,1,m) 131 { 132 scanf("%d%d", &a, &b); 133 add_edge(a, b, oo); 134 } 135 printf("%I64d\n", sum - sap(s, t)); 136 } 137 return 0; 138 }
HDU 3879 Base Station
所给的m条边是正收益,所给的n个点是负收益,此时,把正收益的m条边变为点。
那么,对于连接a b两点的边k,这样建图:
1. 源点与k连边,权值为题目所给边权
2. k分别于a和b连边,权值为无穷大
3. 所有节点和汇点连边,权值为该点花费的绝对值
1 #include <vector> 2 #include <list> 3 #include <map> 4 #include <set> 5 #include <queue> 6 #include <deque> 7 #include <stack> 8 #include <algorithm> 9 #include <sstream> 10 #include <iostream> 11 #include <iomanip> 12 #include <cstdio> 13 #include <cstdlib> 14 #include <cstring> 15 #include <cmath> 16 #include <queue> 17 using namespace std; 18 #define pii pair<LL,LL> 19 #define clr(a) memset((a),0,sizeof (a)) 20 #define rep(i,a,b) for(LL i=(a);i<=(LL)(b);i++) 21 #define per(i,a,b) for(LL i=(a);i>=(LL)(b);i--) 22 #define oo 1000000000 23 #define eps 1e-6 24 #define MAXN 85005 25 #define MAXM 2000005 26 #define MOD 1000000007 27 #define debug puts("reach here") 28 #define MP make_pair 29 #define PB push_back 30 #define RI(x) scanf("%d",&x) 31 #define RII(x,y) scanf("%d%d",&x,&y) 32 #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) 33 typedef long long LL; 34 35 struct Edge 36 { 37 int u, v, next; 38 LL w; 39 }E[MAXM]; 40 41 int gap[MAXN], pre[MAXN], cur[MAXN], dis[MAXN]; 42 int n, m, N; 43 int head[MAXN], NE; 44 bool vis[MAXN]; 45 46 void add_edge (int u, int v, int w) 47 { 48 E[NE].u = u; E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; 49 E[NE].u = v; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; 50 } 51 52 inline void checkmin(int &a, int b) {if(a == -1 || a > b)a = b;} 53 54 int sap(int s,int t) 55 { 56 clr(dis); clr(gap); 57 for(int i=0;i<N;++i) cur[i] = head[i]; 58 int u = pre[s] = s, maxflow = 0, aug = -1; 59 gap[0] = N; 60 while(dis[s] < N) 61 { 62 loop:for(int &i = cur[u]; i != -1; i = E[i].next) 63 { 64 int v = E[i].v; 65 if(E[i].w && dis[u] == dis[v]+1) 66 { 67 checkmin(aug, E[i].w); 68 pre[v] = u; 69 u = v; 70 if(v == t) 71 { 72 maxflow += aug; 73 for(u = pre[u]; v != s; v = u, u = pre[u]) 74 { 75 E[cur[u]].w -= aug; 76 E[cur[u]^1].w += aug; 77 } 78 aug=-1; 79 } 80 goto loop; 81 } 82 } 83 int mindis = N; 84 for(int i = head[u]; i!=-1;i = E[i].next) 85 { 86 int v = E[i].v; 87 if(E[i].w && mindis>dis[v]) 88 { 89 cur[u] = i; 90 mindis = dis[v]; 91 } 92 } 93 if((--gap[dis[u]]) == 0) break; 94 gap[dis[u]=mindis+1]++; 95 u = pre[u]; 96 } 97 return maxflow; 98 } 99 100 void init() 101 { 102 NE = 0; 103 memset(head, -1, sizeof head); 104 } 105 106 int main() 107 { 108 int sum, a, b, c; 109 while(RII(n, m) != EOF) 110 { 111 init(); 112 sum = 0; 113 int s = 0, t = n+m+1; 114 N = t + 1; 115 rep(i,1,n) 116 { 117 RI(c); 118 add_edge(i, t, c); 119 } 120 rep(i,1,m) 121 { 122 RIII(a, b, c); 123 add_edge(s, i+n, c); 124 add_edge(i+n, a, oo); 125 add_edge(i+n, b, oo); 126 sum += c; 127 } 128 printf("%d\n", sum - sap(s, t)); 129 } 130 return 0; 131 }
HDU 3996 Gold Mine
对于某片矿i,源点向 i 连一条边,权值为收益; i 向汇点连一条边,权值为花费。对于关联的两点,连一条边,权值为无穷大。答案为总收益 - 最小割。
1 #include <vector> 2 #include <list> 3 #include <map> 4 #include <set> 5 #include <queue> 6 #include <deque> 7 #include <stack> 8 #include <algorithm> 9 #include <sstream> 10 #include <iostream> 11 #include <iomanip> 12 #include <cstdio> 13 #include <cstdlib> 14 #include <cstring> 15 #include <cmath> 16 #include <queue> 17 using namespace std; 18 #define pii pair<int,int> 19 #define clr(a) memset((a),0,sizeof (a)) 20 #define rep(i,a,b) for(int i=(a);i<=(int)(b);i++) 21 #define per(i,a,b) for(int i=(a);i>=(int)(b);i--) 22 #define oo (1LL)<<60 23 #define eps 1e-6 24 #define MAXN 50005 25 #define MAXM 5000010 26 #define MOD 1000000007 27 #define debug puts("here") 28 #define MP make_pair 29 #define PB push_back 30 #define RI(x) scanf("%d",&x) 31 #define RII(x,y) scanf("%d%d",&x,&y) 32 #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) 33 typedef long long LL; 34 35 struct Edge 36 { 37 int u, v, next; 38 LL w; 39 }E[MAXM]; 40 41 int gap[MAXN], pre[MAXN], cur[MAXN], dis[MAXN]; 42 int n, m, N; 43 int head[MAXN], NE; 44 bool vis[MAXN]; 45 int h[105][30]; 46 47 void add_edge (int u, int v, LL w) 48 { 49 E[NE].u = u; E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; 50 E[NE].u = v; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; 51 } 52 53 inline void checkmin(LL &a, LL b) {if(a == -1 || a > b) a = b;} 54 55 LL sap(int s,int t) 56 { 57 clr(dis); clr(gap); 58 for(int i=0;i<N;++i) cur[i] = head[i]; 59 int u = pre[s] = s; 60 LL maxflow = 0, aug = -1; 61 gap[0] = N; 62 while(dis[s] < N) 63 { 64 loop:for(int &i = cur[u]; i != -1; i = E[i].next) 65 { 66 int v = E[i].v; 67 if(E[i].w && dis[u] == dis[v]+1) 68 { 69 checkmin(aug, E[i].w); 70 pre[v] = u; 71 u = v; 72 if(v == t) 73 { 74 maxflow += aug; 75 for(u = pre[u]; v != s; v = u, u = pre[u]) 76 { 77 E[cur[u]].w -= aug; 78 E[cur[u]^1].w += aug; 79 } 80 aug=-1; 81 } 82 goto loop; 83 } 84 } 85 int mindis = N; 86 for(int i = head[u]; i!=-1;i = E[i].next) 87 { 88 int v = E[i].v; 89 if(E[i].w && mindis>dis[v]) 90 { 91 cur[u] = i; 92 mindis = dis[v]; 93 } 94 } 95 if((--gap[dis[u]]) == 0) break; 96 gap[dis[u]=mindis+1]++; 97 u = pre[u]; 98 } 99 return maxflow; 100 } 101 102 void init() 103 { 104 NE = 0; 105 memset(head, -1, sizeof head); 106 } 107 108 int main() 109 { 110 int t, a, b, c, src, des, id, cas = 1; 111 LL sum; 112 RI(t); 113 while(t--) 114 { 115 RI(n); 116 init(); 117 src = 0, des = 50000; 118 id = 0; sum = 0; 119 rep(i,1,n) 120 { 121 RI(m); 122 rep(j,1,m) 123 { 124 ++id; 125 RIII(a,b,c); 126 h[i][j] = id; 127 sum += b; 128 add_edge(src, id, b); 129 add_edge(id, des, a); 130 rep(k,1,c) 131 { 132 RII(a, b); 133 add_edge(id, h[a][b], oo); 134 } 135 } 136 } 137 N = id + 2; 138 printf("Case #%d: %I64d\n", cas++, sum - sap(src, des)); 139 } 140 return 0; 141 }
CSU 1319 CX's dream
这道题是zzy师兄出的题目,需要在流网络最大权闭包的基础上求出可获得的最多节点数,对于网络流里获取最多节点数,一般需要加一个偏移量,最后取模就可以了。因为这道题求的是最多实现的梦想,所以对于付出节点,即使其为正数,也不加偏移,只在梦想节点加偏移,最后答案就是“总的梦想数 - 总偏移”。这道题需要用long long。
1 #include <vector> 2 #include <list> 3 #include <map> 4 #include <set> 5 #include <queue> 6 #include <deque> 7 #include <stack> 8 #include <algorithm> 9 #include <sstream> 10 #include <iostream> 11 #include <iomanip> 12 #include <cstdio> 13 #include <cstdlib> 14 #include <cstring> 15 #include <cmath> 16 #include <queue> 17 using namespace std; 18 #define pii pair<LL,LL> 19 #define clr(a) memset((a),0,sizeof (a)) 20 #define rep(i,a,b) for(LL i=(a);i<=(LL)(b);i++) 21 #define per(i,a,b) for(LL i=(a);i>=(LL)(b);i--) 22 #define oo ((LL)2000000007)*((LL)2000000007) 23 #define eps 1e-6 24 #define MAXN 5005 25 #define MAXM 2000005 26 #define MOD 1000000007 27 #define debug puts("reach here") 28 #define MP make_pair 29 #define PB push_back 30 #define RI(x) scanf("%lld",&x) 31 #define RII(x,y) scanf("%lld%lld",&x,&y) 32 #define RIII(x,y,z) scanf("%d%d%d",&x,&y,&z) 33 typedef long long LL; 34 35 struct Edge 36 { 37 LL u, v, next; 38 LL w; 39 }E[MAXM]; 40 41 LL gap[MAXN], pre[MAXN], cur[MAXN], dis[MAXN]; 42 LL n, m; 43 LL N; 44 LL head[MAXN], NE; 45 bool vis[MAXN]; 46 47 void add_edge (LL u, LL v, LL w) 48 { 49 E[NE].u = u; E[NE].v = v; E[NE].w = w; E[NE].next = head[u]; head[u] = NE++; 50 E[NE].u = v; E[NE].v = u; E[NE].w = 0; E[NE].next = head[v]; head[v] = NE++; 51 } 52 53 inline void checkmin(LL &a,LL b) {if(a == -1 || a > b)a = b;} 54 55 LL sap(LL s,LL t) 56 { 57 clr(dis); clr(gap); 58 for(LL i=0;i<N;++i) cur[i]=head[i]; 59 LL u=pre[s]=s; 60 LL maxflow=0; 61 LL aug=-1; 62 gap[0]=N; 63 while(dis[s]<N) 64 { 65 loop:for(LL &i=cur[u];i!=-1;i=E[i].next) 66 { 67 LL v=E[i].v; 68 if(E[i].w && dis[u]==dis[v]+1) 69 { 70 checkmin(aug,E[i].w); 71 pre[v]=u; 72 u=v; 73 if(v==t) 74 { 75 maxflow += aug; 76 for(u=pre[u];v!=s;v=u,u=pre[u]) 77 { 78 E[cur[u]].w-=aug; 79 E[cur[u]^1].w+=aug; 80 } 81 aug=-1; 82 } 83 goto loop; 84 } 85 } 86 LL mindis=N; 87 for(LL i=head[u];i!=-1;i=E[i].next) 88 { 89 LL v=E[i].v; 90 if(E[i].w && mindis>dis[v]) 91 { 92 cur[u]=i; 93 mindis=dis[v]; 94 } 95 } 96 if((--gap[dis[u]])==0) break; 97 gap[dis[u]=mindis+1]++; 98 u=pre[u]; 99 } 100 return maxflow; 101 } 102 103 void init() 104 { 105 NE = 0; 106 memset(head, -1, sizeof head); 107 } 108 109 int main() 110 { 111 LL a, k; 112 LL sum, v; 113 LL M = 5000; 114 while(scanf("%lld%lld", &n, &m) != EOF) 115 { 116 init(); 117 LL s = 0, t = n + m + 1; 118 sum = 0; 119 N = t + 1; 120 rep(i,1,n) 121 { 122 scanf("%lld", &v); 123 add_edge(s, i, v*M+1); 124 sum += v; 125 } 126 rep(i,1,m) 127 { 128 scanf("%lld", &v); 129 if(v > 0) 130 { 131 sum += v; 132 add_edge(s, i+n, v*M); 133 } 134 else 135 add_edge(i+n, t, -v*M); 136 } 137 rep(i,1,n) 138 { 139 scanf("%lld", &k); 140 rep(j,1,k) 141 { 142 scanf("%lld", &a); 143 add_edge(i, a+n, oo); 144 } 145 } 146 LL ans = sap(s, t); 147 printf("%lld %lld\n", sum - ans/M, n - (ans%M)); 148 } 149 return 0; 150 }