方格取数 【网络流24题】【最小割】

输入输出样例

输入 #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\n",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\n",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 }
View Code

猜你喜欢

转载自www.cnblogs.com/orangeko/p/12670800.html