解法一、网络流
相邻的点染不同颜色:
(行数+列数)为奇数的染成白色,(行数+列数)为偶数的染成白色
source = 0, sink = n*n+1.
source到每个白点连接,流量为白点的值
黑点到sink连接,流量为黑点的值
每个白点与其周围的黑点连接,流量为INT_MAX
所有点的值的总和 - 最大流量 = 所求答案
以下是抄来的原理:
点覆盖集:无向图G的一个点集,使得该图中所有边都至少有一个端点在该集合内。
最小点权覆盖集:在带点权无向图G中,点权之和最小的覆盖集。
点独立集:无向图G的一个点集,使得任两个在该集合中的点在原图中都不相邻。
最大点权独立集:在带权无向图G中,点权之和最大的独立集。
定理:
1. 二分图的最小点权覆盖集=最小割=最大流
2. 二分图的最大点权独立集=总权-最小点权覆盖集
1 #include <cstdio> 2 #include <climits> 3 #include <cstring> 4 #include <queue> 5 6 #define MAXN 20 7 8 const int source = 0; 9 int n, G[MAXN*MAXN+10][MAXN*MAXN+10], layer[MAXN*MAXN+10], total, sink; 10 bool vis[MAXN*MAXN+10]; 11 12 bool bfs() 13 { 14 memset(layer, -1, sizeof(layer)); 15 std::queue<int> q; 16 q.push(source); 17 layer[source] = 0; 18 while(q.empty()==false){ 19 int u = q.front(); 20 q.pop(); 21 for(int v = 1; v <= sink; ++v){ 22 if(layer[v] == -1 && G[u][v] > 0){ 23 layer[v] = layer[u] + 1; 24 if(v == sink) 25 return true; 26 q.push(v); 27 } 28 } 29 } 30 return false; 31 } 32 33 int dinic() 34 { 35 int max_flow = 0; 36 while(bfs() == true){ 37 memset(vis,false,sizeof(vis)); 38 vis[source] = true; 39 int st[MAXN*MAXN+10]; 40 int top = 0; 41 st[++top]= source; 42 while(top > 0) { 43 int u = st[top]; 44 if(u == sink) { 45 int current = INT_MAX; 46 int key_path; 47 for(int i = 1; i < top; ++i) { 48 int s = st[i]; 49 int e = st[i+1]; 50 if(current > G[s][e]) { 51 current = G[s][e]; 52 key_path = i; 53 } 54 } 55 for(int i = 1; i < top; ++i) { 56 int s = st[i]; 57 int e = st[i+1]; 58 G[s][e] -= current; 59 G[e][s] += current; 60 } 61 62 max_flow += current; 63 while(top > key_path) { 64 vis[st[top--]] = false; 65 } 66 } 67 else { 68 int v; 69 for(v= 1; v <= sink; ++v) { 70 if(layer[v] == layer[u]+1 && vis[v] == false && G[u][v] > 0) { 71 vis[v] = true; 72 st[++top] = v; 73 break; 74 } 75 } 76 if(v == sink+1) { 77 top--; 78 } 79 } 80 } 81 } 82 return max_flow; 83 } 84 85 void init() 86 { 87 memset(G, 0, sizeof(G)); 88 total = 0; 89 sink = n*n+1; 90 for(int i = 1, input_buffer; i <= n*n; ++i){ 91 scanf("%d", &input_buffer); 92 total += input_buffer; 93 int row = (i-0.1) / n + 1; 94 int column = (i % n == 0) ? (n) : (i % n); 95 // if (row + column) is odd number, link source to this cell. 96 if( (row + column)&1 ){ 97 G[source][i] = input_buffer; 98 99 if(i%n != 1) 100 G[i][i-1] = INT_MAX; 101 if(i%n != 0) 102 G[i][i+1] = INT_MAX; 103 if(i > n) 104 G[i][i-n] = INT_MAX; 105 if(i <= n*n-n) 106 G[i][i+n] = INT_MAX; 107 } 108 // if (row + column) is even number, link this cell to sink. 109 else 110 G[i][sink] = input_buffer; 111 } 112 } 113 114 int main(int argc, char const *argv[]) 115 { 116 // freopen("in", "r", stdin); 117 while(~scanf("%d", &n)){ 118 init(); 119 printf("%d ", total - dinic()); 120 } 121 return 0; 122 }