[codevs 1907] 方格取数3
题解:
二分图染色、最大点权独立集。
因为要用到最大独立集的一些思路,故先写了一篇最大独立集的题解:
http://blog.csdn.net/qq_21110267/article/details/43371311
最大点权独立集可以类比到最大独立集,同样求解它的对称问题——最小点权覆盖问题(思路见上),点权和-最小点权覆盖=最大点权独立集。
那么怎么求最小点权覆盖呢?
想一想最小割模型,割的性质是不存在一条s-t的路径,我们已经建立了二分图模型,假设u是左侧的结点,v是右侧的结点,那么s-u、u-v、v-t必定有一条在最小割中,如果人为的令u-v不在最小割中(设边权为INF),那么就简化为了s-u、v-t至少一条边在最小割中,正符合了最小点权覆盖中相邻点(u、v)至少一个点被选中,我们把s-u的容量设为点u的权值,v-t的容量设为点t的权值,这样s-u在最小割中就对应着u被选中,而v-t在最小割中就对应着v被选中,这样就把最小点权覆盖问题转化为了最大流问题。
代码:
总时间耗费: 3ms
总内存耗费: 492B
#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 1000 + 10;
const int INF = 1000000007;
struct Edge {
int from, to, cap, flow;
};
vector<Edge> edges;
vector<int> G[maxn];
int val[maxn][maxn];
void AddEdge(int from, int to, int cap) {
edges.push_back((Edge){from, to, cap, 0});
edges.push_back((Edge){to, from, 0, 0});
int sz = edges.size();
G[from].push_back(sz-2);
G[to].push_back(sz-1);
}
int m, n, s, t;
int d[maxn], p[maxn], cur[maxn], num[maxn];
bool vis[maxn];
bool BFS() {
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow) {
vis[e.to] = true;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int u, int a) {
if(u == t || a == 0) return a;
int flow = 0, f;
for(int &i = cur[u]; i < G[u].size(); i++) {
Edge& e = edges[G[u][i]];
if(d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
e.flow += f;
edges[G[u][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int Maxflow() {
int flow = 0;
while(BFS()) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, INF);
}
return flow;
}
int main() {
cin >> m >> n;
s = 0; t = m * n + 1;
int tot = 0;
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++) {
cin >> val[i][j];
tot += val[i][j];
}
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++) {
int u = i*n + j + 1;
if((i+j)&1) {
if(i > 0) AddEdge(u, u-n, INF);
if(j > 0) AddEdge(u, u-1, INF);
if(i < m-1) AddEdge(u, u+n, INF);
if(j < n-1) AddEdge(u, u+1, INF);
AddEdge(s, u, val[i][j]);
} else {
AddEdge(u, t, val[i][j]);
}
}
int ans = Maxflow();
cout << tot - ans << endl;
return 0;
}