http://acm.hdu.edu.cn/showproblem.php?pid=1565
题意:
给出N*N的格子,每个格子里都有数字,问你怎么样取数字能使其和最大,前提是取出来的格子不能两两相邻。
坑爹:
一开始以为不是选奇数位置就是偶数位置就能解出来的水题,仔细看了下题意发现天真了。。。
解法:
这道题可以用网络流的最小割来做
最大流 = 最小割 = 最小点权覆盖集 = sum - 最大点权独立集
先设置一个源点(0)和一个汇点( n*n+1),一开始初始化的时候把源点到所有 (i+j)%2 ==1的格子全部给个值,
然后初始化把汇点到所有 (i+j) %2 == 0的格子也给个值,值就是这个格子数字。还有,我在记录这些值的二维数组temp[i][j]
中的下标 i 和 j 是代表第几个格子,比如说:
3
987
654
321
这样的数据的话,初始化源点的格子分别为9,7,5,3,1,但是9是第1个,3是第7个(一行一行数)。
然后还有一个步骤就是将所有的点与他附近的点的temp值都为INF(最大值),这样就形成了一个图,
问题就转换为花费最少的流量将这个图的源点和汇点切断(最小割),剩下的值就能达到最大了。


1 #include<iostream> 2 #include<queue> 3 using namespace std; 4 5 const int maxn = 20 + 10; 6 const int INF = 0x3fffffff; 7 int map[maxn][maxn]; 8 int point[4][2] = {0,1,0,-1,1,0,-1,0}; 9 int temp[maxn*maxn][maxn*maxn]; 10 int n; 11 12 bool judge(int x,int y) // 判断是否越界 13 { 14 if(x>0 && x<=n && y>0 && y<=n) 15 { 16 return 1; 17 } 18 return 0; 19 } 20 21 int BFS(int s,int t) 22 { 23 int flow = 0; 24 while(1) 25 { 26 int pre[maxn*maxn]; 27 memset(pre,-1,sizeof(pre)); 28 int i; 29 int min = INF;//找出最小流量 30 queue<int> Q; //放进去的代表是第几个 31 Q.push(s); 32 int begin; 33 while(!Q.empty()) 34 { 35 begin = Q.front(); 36 Q.pop(); 37 for(i=1; i<=n*n+1; i++) 38 { 39 if(temp[begin][i] > 0 && pre[i] == -1) 40 { 41 Q.push(i); 42 if(temp[begin][i] < min) 43 { 44 min = temp[begin][i]; 45 } 46 pre[i] = begin; 47 } 48 } 49 if(pre[t] != -1) 50 { 51 break; 52 } 53 } 54 55 int u = t; 56 if(pre[u] <= 0) 57 { 58 break; 59 } 60 61 while(u != s) // 减去流量 62 { 63 temp[pre[u]][u] -= min; 64 temp[u][pre[u]] += min; 65 u = pre[u]; 66 } 67 flow += min; 68 } 69 return flow; 70 } 71 72 73 int main() 74 { 75 while(cin>>n) 76 { 77 memset(map,0,sizeof(map)); 78 memset(temp,0,sizeof(temp)); 79 int i; 80 int j; 81 int sum = 0; 82 for(i=1; i<=n; i++) 83 { 84 for(j=1; j<=n; j++) 85 { 86 cin>>map[i][j]; 87 sum += map[i][j]; 88 } 89 } 90 91 // 0作为源点 n*n+1作为汇点 92 for(i=1; i<=n; i++) 93 { 94 for(j=1; j<=n; j++) 95 { 96 if( (i+j)%2 == 0 ) 97 { 98 temp[0][(i-1)*n+j] = map[i][j]; 99 } 100 else 101 { 102 temp[(i-1)*n+j][n*n+1] = map[i][j]; 103 } 104 } 105 } 106 107 // 将与源点相连的点的相邻的值附上INF 108 for(i=1; i<=n; i++) 109 { 110 for(j=1; j<=n; j++) 111 { 112 for(int k=0; k<4; k++) 113 { 114 int x = i + point[k][0]; 115 int y = j + point[k][1]; 116 if( judge(x,y) && (i+j) % 2 == 0 ) 117 { 118 temp[(i-1)*n+j][(x-1)*n+y] = INF; // (i-1)*n+j 代表的是第几个 119 // 123 120 // 456 121 // 789 的话7的话就是第7个 122 } 123 } 124 } 125 } 126 int s = 0;//源点 127 int t = n*n+1;//汇点 128 129 cout<<sum-BFS(s,t)<<endl; 130 } 131 return 0; 132 }