【费用流】 ICPC 2016 China Final J. Mr.Panda and TubeMaster

表示“必须选”的模型

题目大意


题目分析

一个格子有四种方式看上去很难处理。将横竖两个方向分开考虑,会发现:因为收益只与相邻格子是否连通有关,所以可以将一个格子拆成表示横竖两个方向的,互相独立的点。

上图的格子里四个方向红边表示的就是一个格子的可能方向;拆点后所连蓝边的容量为1,费用即为连通两个格子的收益。

但是这样建图不能够表示某些格子必须要选。

考虑一个格子如果被选择了会发生什么:因为每个格子都处在环上,那么被选择的网格一定可以通过其他节点走到汇点。这意味着一个格子拆成的两个节点之间的边就可以先不建,而若最大流不等于网格总数,即有节点不可能被合法选中。

建图的时候一定要先理解清楚,因为有很多种错误方式,下图就是其中一个。

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cctype>
  4 #include<cstring>
  5 #include<algorithm>
  6 const int maxn = 2035;
  7 const int maxm = 100035;
  8 const int INF = 2e9;
  9 
 10 struct Edge
 11 {
 12     int u,v,f,c,cst;
 13     Edge(int a=0, int b=0, int c=0, int d=0, int e=0):u(a),v(b),f(c),c(d),cst(e) {}
 14 }edges[maxm];
 15 int sne,n,m,S,T;
 16 bool ess[33][33],inq[maxn];
 17 int tagl[33][33],tagr[33][33],valc[33][33],valr[33][33];  //tagl为入点,tagr为出点
 18 int edgeTot,head[maxn],nxt[maxm],flw[maxn],cst[maxn],bck[maxn];
 19 
 20 int read()
 21 {
 22     char ch = getchar();
 23     int num = 0, fl = 1;
 24     for (; !isdigit(ch); ch=getchar())
 25         if (ch=='-') fl = -1;
 26     for (; isdigit(ch); ch=getchar())
 27         num = (num<<1)+(num<<3)+ch-48;
 28     return num*fl;
 29 }
 30 void addedge(int u, int v, int c, int cst)
 31 {
 32     edges[edgeTot] = Edge(u, v, 0, c,  cst), nxt[edgeTot] = head[u], head[u] = edgeTot++;
 33     edges[edgeTot] = Edge(v, u, 0, 0, -cst), nxt[edgeTot] = head[v], head[v] = edgeTot++;
 34 }
 35 void maxFlow()
 36 {
 37     int mxFlw = 0, cost = 0;
 38     for (;;)
 39     {
 40         std::queue<int> q;
 41         memset(flw, 0, sizeof flw);
 42         memset(bck, 0, sizeof bck);
 43         memset(cst, 0x3f3f3f3f, sizeof cst);
 44         q.push(S), flw[S] = INF, cst[S] = 0;
 45         for (int tmp; q.size(); )
 46         {
 47             tmp = q.front(), q.pop(), inq[tmp] = 0;
 48             for (int i=head[tmp]; i!=-1; i=nxt[i])
 49             {
 50                 int v = edges[i].v;
 51                 if (cst[tmp]+edges[i].cst < cst[v]&&edges[i].f < edges[i].c){
 52                     bck[v] = i, cst[v] = cst[tmp]+edges[i].cst;
 53                     flw[v] = std::min(flw[tmp], edges[i].c-edges[i].f);
 54                     if (!inq[v]) inq[v] = 1, q.push(v);
 55                 }
 56             }
 57         }
 58         if (!flw[T]) break;
 59         for (int i=T; i!=S; i=edges[bck[i]].u)
 60             edges[bck[i]].f += flw[T], edges[bck[i]^1].f -= flw[T];
 61         mxFlw += flw[T], cost += cst[T]*flw[T];
 62     }
 63     if (mxFlw!=n*m) puts("Impossible");
 64     else printf("%d
",-cost);
 65 }
 66 int main()
 67 {
 68     sne = read();
 69     for (int cse=1; cse<=sne; cse++)
 70     {
 71         printf("Case #%d: ",cse);
 72         memset(ess, 0, sizeof ess);
 73         memset(head, -1, sizeof head);
 74         edgeTot = 0, n = read(), m = read();
 75         for (int i=1; i<=n; i++)
 76             for (int j=1; j<m; j++)
 77                 valc[i][j] = read();
 78         for (int i=1; i<n; i++)
 79             for (int j=1; j<=m; j++)
 80                 valr[i][j] = read();
 81         for (int i=1, cnt=0; i<=n; i++)
 82             for (int j=1; j<=m; j++)
 83                 tagl[i][j] = ++cnt, tagr[i][j] = ++cnt;
 84         S = 0, T = tagr[n][m]+1;
 85         for (int i=1; i<=n; i++)
 86             for (int j=1; j<=m; j++)
 87                 if ((i+j)&1){    //为避免重复建边的处理技巧
 88                     if (j+1 <= m) addedge(tagl[i][j], tagr[i][j+1], 1, -valc[i][j]);
 89                     if (j-1 >= 1) addedge(tagl[i][j], tagr[i][j-1], 1, -valc[i][j-1]);
 90                 }else{
 91                     if (i+1 <= n) addedge(tagl[i][j], tagr[i+1][j], 1, -valr[i][j]);
 92                     if (i+1 >= 1) addedge(tagl[i][j], tagr[i-1][j], 1, -valr[i-1][j]);
 93                 }
 94         for (int i=read(); i; i--) ess[read()][read()] = 1;
 95         for (int i=1; i<=n; i++)
 96             for (int j=1; j<=m; j++)
 97             {
 98                 addedge(S, tagl[i][j], 1, 0);
 99                 addedge(tagr[i][j], T, 1, 0);
100                 if (!ess[i][j]) addedge(tagl[i][j], tagr[i][j], 1, 0);
101             }
102         maxFlow();
103     }
104     return 0;
105 } 

END

原文地址:https://www.cnblogs.com/antiquality/p/10356482.html