HDU1569 方格取数(2) —— 二分图点带权最大独立集、最小割最大流

题目链接:https://vjudge.net/problem/HDU-1569

方格取数(2)

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6876    Accepted Submission(s): 2198


Problem Description
给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
 
Input
包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
 
Output
对于每个测试实例,输出可能取得的最大的和
 
Sample Input
3 3 75 15 21 75 15 28 34 70 5
 
Sample Output
188
 
Author
ailyanlu
 
Source

题解:

1.将n*m的格子建模成二分图。

2.在二分图的基础上添加源点S和汇点T, 然后从S向所有X集合中的点连一条边, 所有Y集合中的点向T连一条边, 容量均为该点的权值。

3.X集合的结点与Y集合的结点之间的边的容量为无穷大。在此题中,如果是格子相邻,就需要连边,且是X-->Y。

4.因此,对于该图中的任意一个割, 将割中的边所对应的结点删掉,就是一个符合条件的解,权值和为所有权和减去割的容量。

5.根据4可得:只要求出最小割, 就能求出最大权值和独立集。

代码如下:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <vector>
  6 #include <cmath>
  7 #include <queue>
  8 #include <stack>
  9 #include <map>
 10 #include <string>
 11 #include <set>
 12 using namespace std;
 13 typedef long long LL;
 14 const int INF = 2e9;
 15 const LL LNF = 9e18;
 16 const int mod = 1e9+7;
 17 const int MAXM = 1e5+10;
 18 const int MAXN = 2500+10;
 19 
 20 struct Edge
 21 {
 22     int to, next, cap, flow;
 23 }edge[MAXM];
 24 int tot, head[MAXN];
 25 int gap[MAXN], dep[MAXN], pre[MAXN], cur[MAXN];
 26 
 27 void init()
 28 {
 29     tot = 0;
 30     memset(head, -1, sizeof(head));
 31 }
 32 
 33 void add(int u, int v, int w)
 34 {
 35     edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0;
 36     edge[tot].next = head[u]; head[u] = tot++;
 37     edge[tot].to = u; edge[tot].cap = 0; edge[tot].flow = 0;
 38     edge[tot].next = head[v]; head[v] = tot++;
 39 }
 40 
 41 int sap(int start, int end, int nodenum)
 42 {
 43     memset(dep, 0, sizeof(dep));
 44     memset(gap, 0, sizeof(gap));
 45     memcpy(cur, head, sizeof(head));
 46     int u = pre[start] = start, maxflow = 0,aug = INF;
 47     gap[0] = nodenum;
 48     while(dep[start]<nodenum)
 49     {
 50         loop:
 51         for(int i = cur[u]; i!=-1; i = edge[i].next)
 52         {
 53             int v = edge[i].to;
 54             if(edge[i].cap-edge[i].flow && dep[u]==dep[v]+1)
 55             {
 56                 aug = min(aug, edge[i].cap-edge[i].flow);
 57                 pre[v] = u;
 58                 cur[u] = i;
 59                 u = v;
 60                 if(v==end)
 61                 {
 62                     maxflow += aug;
 63                     for(u = pre[u]; v!=start; v = u,u = pre[u])
 64                     {
 65                         edge[cur[u]].flow += aug;
 66                         edge[cur[u]^1].flow -= aug;
 67                     }
 68                     aug = INF;
 69                 }
 70                 goto loop;
 71             }
 72         }
 73         int mindis = nodenum;
 74         for(int i = head[u]; i!=-1; i = edge[i].next)
 75         {
 76             int v=edge[i].to;
 77             if(edge[i].cap-edge[i].flow && mindis>dep[v])
 78             {
 79                 cur[u] = i;
 80                 mindis = dep[v];
 81             }
 82         }
 83         if((--gap[dep[u]])==0)break;
 84         gap[dep[u]=mindis+1]++;
 85         u = pre[u];
 86     }
 87     return maxflow;
 88 }
 89 
 90 int n, m, g[55][55];
 91 int main()
 92 {
 93     while(scanf("%d%d", &n, &m)!=EOF)
 94     {
 95         int sum = 0;
 96         for(int i = 0; i<n; i++)
 97         for(int j = 0; j<m; j++)
 98             scanf("%d", &g[i][j]), sum += g[i][j];
 99 
100         int start = n*m, end = n*m+1;
101         init();
102         for(int i = 0; i<n; i++)
103         for(int j = 0; j<m; j++)
104         {
105             if((i+j)%2)
106             {
107                 add(start, i*m+j, g[i][j]);
108                 if(i!=0)  add(i*m+j, (i-1)*m+j, INF);
109                 if(i!=n-1) add(i*m+j, (i+1)*m+j, INF);
110                 if(j!=0) add(i*m+j, i*m+j-1, INF);
111                 if(j!=m-1) add(i*m+j, i*m+j+1, INF);
112             }
113             else
114                 add(i*m+j, end, g[i][j]);
115         }
116 
117         sum -= sap(start, end, n*m+2);
118         printf("%d
", sum);
119     }
120 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8124507.html