[codevs 1907] 方格取数3

来源:互联网 发布:lua map数组 编辑:程序博客网 时间:2024/05/15 00:08

[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;}


0 0
原创粉丝点击