【网络流之最大权闭包专题】解题报告

 

 最大权闭包模型中源点与正收益的点连边,负收益的点与汇点连边,容量取绝对值,然后相关联的点之间之间连容量为无穷大的边。

 具体可参见胡伯涛:《最小割模型在信息学竞赛中的应用》

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

 

你可能感兴趣的:(网络流)