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


posted @ 2015-02-01 14:18  wfwbz  阅读(122)  评论(0编辑  收藏  举报