[codevs 1907] 方格取数3
[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; }