输入输出样例
输入 #1
3 3 1 2 3 3 2 3 2 3 1
输出 #1
11
思路
因为要保证一个点不能和他有共同边的点接触
很容易想到把所有点划分为两个阵营
显然一个横纵坐标相加为偶数的点
其所接触的点横纵坐标相加为奇数
于是得到二分图划分的依据:横纵坐标相加和的奇偶性
把偶数阵营连边S,奇数阵营连边T
奇偶阵营之间连边 INF
就是本踢的二分图模型
通过观察可以发现,图中向S、T连边象征了一种抉择
当两个有公共边的点可以流通时,显然是不满足要求的
考虑删除这种边且使得花费最小
发现这是个最小割问题
通过在相邻点之间连流量为 inf 的边可以保证割去的一定是某个点连向 S 或 T 的边
这个时候答案就等于所有点的总权值和 - 最小割 = SUM - MAXFLOW
CODE
1 #include <bits/stdc++.h> 2 #define dbg(x) cout << #x << "=" << x << endl 3 #define eps 1e-8 4 #define pi acos(-1.0) 5 6 using namespace std; 7 typedef long long LL; 8 9 const LL inf = 0x7f7f7f7f; 10 11 template<class T>inline void read(T &res) 12 { 13 char c;T flag=1; 14 while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; 15 while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; 16 } 17 18 namespace _buff { 19 const size_t BUFF = 1 << 19; 20 char ibuf[BUFF], *ib = ibuf, *ie = ibuf; 21 char getc() { 22 if (ib == ie) { 23 ib = ibuf; 24 ie = ibuf + fread(ibuf, 1, BUFF, stdin); 25 } 26 return ib == ie ? -1 : *ib++; 27 } 28 } 29 30 int qread() { 31 using namespace _buff; 32 int ret = 0; 33 bool pos = true; 34 char c = getc(); 35 for (; (c < '0' || c > '9') && c != '-'; c = getc()) { 36 assert(~c); 37 } 38 if (c == '-') { 39 pos = false; 40 c = getc(); 41 } 42 for (; c >= '0' && c <= '9'; c = getc()) { 43 ret = (ret << 3) + (ret << 1) + (c ^ 48); 44 } 45 return pos ? ret : -ret; 46 } 47 48 const int maxn = 200007; 49 50 int n, m; 51 int s, t; 52 53 struct edge{ 54 int from,to; 55 LL cap,flow; 56 }; 57 58 struct DINIC { 59 int head[maxn << 1], nxt[maxn << 1], edge[maxn << 1], cnt; 60 int cap[maxn << 1], depth[maxn << 1]; 61 62 void init() { 63 cnt = 1; 64 memset(head, 0, sizeof(head)); 65 } 66 67 void BuildGraph(int u, int v, int w) { 68 ++cnt; 69 edge[cnt] = v; 70 nxt[cnt] = head[u]; 71 cap[cnt] = w; 72 head[u] = cnt; 73 74 ++cnt; 75 edge[cnt] = u; 76 nxt[cnt] = head[v]; 77 cap[cnt] = 0; 78 head[v] = cnt; 79 } 80 81 queue<int> q; 82 83 bool bfs() { 84 memset(depth, 0, sizeof(depth)); 85 depth[s] = 1; 86 q.push(s); 87 while(!q.empty()) { 88 int u = q.front(); 89 q.pop(); 90 for ( int i = head[u]; i; i = nxt[i] ) { 91 int v = edge[i]; 92 if(depth[v]) { 93 continue; 94 } 95 if(cap[i]) { 96 depth[v] = depth[u] + 1; 97 q.push(v); 98 } 99 } 100 } 101 //printf("dep[%d]:%d ",t, depth[t]); 102 return depth[t]; 103 } 104 105 int dfs(int u, int dist) { 106 if(u == t) { 107 return dist; 108 } 109 int flow = 0; 110 for ( int i = head[u]; i && dist; i = nxt[i] ) { 111 if(cap[i] == 0) 112 continue; 113 int v = edge[i]; 114 if(depth[v] != depth[u] + 1) { 115 continue; 116 } 117 int res = dfs(v, min(cap[i], dist)); 118 cap[i] -= res; 119 cap[i ^ 1] += res; 120 //printf("cap[%d]:%d ",t, cap[t]); 121 dist -= res; 122 flow += res; 123 } 124 return flow; 125 } 126 127 int maxflow() { 128 int ans = 0; 129 while(bfs()) { 130 ans += dfs(s, inf); 131 } 132 return ans; 133 } 134 } dinic; 135 136 int dr[4] = {1, 0, -1, 0}; 137 int dc[4] = {0, 1, 0, -1}; 138 139 inline int id(int a, int b) { 140 return (a - 1) * n + b; 141 } 142 143 int main() 144 { 145 //freopen("data.txt", "r", stdin); 146 read(m); read(n); 147 int sum = 0; 148 s = 0, t = n * m + 1; 149 dinic.init(); 150 for ( int i = 1; i <= m; ++i ) { 151 for ( int j = 1; j <= n; ++j ) { 152 int x; 153 read(x); 154 sum += x; 155 if(((i + j) & 1) == 0) { 156 dinic.BuildGraph(s, id(i, j), x); 157 for ( int k = 0; k < 4; ++k ) { 158 int xx = i + dr[k], yy = j + dc[k]; 159 if(xx <= m && xx >= 1 && yy <= n && yy >= 1) { 160 dinic.BuildGraph(id(i, j), id(xx, yy), inf); 161 } 162 163 } 164 } 165 else { 166 dinic.BuildGraph(id(i, j), t, x); 167 } 168 } 169 } 170 int res = dinic.maxflow(); 171 //dbg(res); 172 cout << sum - res << endl; 173 return 0; 174 }