hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)
/** 转自:http://blog.csdn.net/u011498819/article/details/20772147 题目:hdu1569 方格取数(2) 链接:https://vjudge.net/problem/HDU-1569 题意:一个方格n*m,取出一些点,要求两两不相邻,求最大和。 思路:
建图过程:对于二维矩阵,如果(i+j)%2==0,那么放在X集,s->(i-1)*m+j, cap = 元素值。
否则放在Y集, (i-1)*m+j->t, cap = 元素值。
如果u与v相邻,且u为X集的点,v为Y集的点,u->v,cap = INF.
建图,相邻的点有一条边,则建立了一个二分图,求最大点权独立集(所取点两两无公共边,权值和最大), 问题转化为求总权和-最小点权覆盖集(点集I覆盖所有边,点权之和最小), (对应于原题,就是求拿掉最小点集,这些点覆盖所有边,拿掉后,每个点必然两两不相邻, 否则:假设u,v相邻,则u->v这条边未被覆盖,矛盾), 在建立超级源汇点s,t,s连向所有X中的点(设二分图G(X,Y)),Y联向t,,权值为点权, 原来X->Y的所有边权值改为inf,问题转化为:求s->t最小割(一组权值和最小的割边集,去掉后s->t不连通), 而每去掉一条割边,相当于去掉原图一个点,这个点必然牵着下面X->Y的边,故最小割即为最小点权覆盖集! (部分证明:摘自某大牛:可以这样理解:X到Y的边权为INF,自然不会成为最小割中的边,那就只有可能 是S到X和Y到T中的边,而:S到X中点x的边e1, 权为点x的点权,点x和Y中的所有临边e2,都需要受 到e1的流量的限制,同样,X到Y中点y的所有边也会受到点y到T的容量限制。这样求得割就能保证覆 盖掉所有的边。 我们可以用反证法证明一下:假设有边<x, y>没有被覆盖掉,则边<S, x>流量为0且边<y, T>流量为0, 而<x, y>流量为INF,自然可以找到一条S到T的增流路径<S, x, y, T>,与以求得流为最大流相矛盾, 则可以说明,在最大流的情况下,所有的边都已经被覆盖掉。) 结论(二分图):最小点权覆盖集=最小割=最大流; 最大点权覆盖集=总权和-最小点权覆盖集 */ #include<iostream> #include<cstring> #include<vector> #include<map> #include<cstdio> #include<algorithm> #include<queue> using namespace std; const long long MAS = 1e13; const int INF = 0x3f3f3f3f; typedef long long LL; const int N = 50*50+10;///拆点法,注意要乘以个2. struct Edge{ int from, to, cap, flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct Dinic{ int n, m, s, t; vector<Edge> edges; vector<int> G[N]; bool vis[N]; int d[N]; int cur[N]; void init(int n) { this->n = n; for(int i = 0; i <= n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m = edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } 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] = 1; d[e.to] = d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a) { if(x==t||a==0) return a; int flow = 0, f; for(int &i = cur[x]; i < G[x].size(); i++) { Edge& e = edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0) { e.flow += f; edges[G[x][i]^1].flow -= f; flow += f; a -= f; if(a==0) break; } } return flow; } int Maxflow(int s,int t) { this->s = s, this->t = t; int flow = 0; while(BFS()) { memset(cur, 0, sizeof cur); flow += DFS(s,INF); } return flow; } }; int main() { int n, m; while(scanf("%d%d",&n,&m)==2) { int s = 0, t = n*m+1; Dinic dinic; dinic.init(t); int w; int sum = 0; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ scanf("%d",&w); sum += w; if((i+j)%2==0){///放左边 dinic.AddEdge(s,(i-1)*m+j,w); if(j+1<=m){ dinic.AddEdge((i-1)*m+j,(i-1)*m+j+1,INF); } if(j-1>=1){ dinic.AddEdge((i-1)*m+j,(i-1)*m+j-1,INF); } if(i+1<=n){ dinic.AddEdge((i-1)*m+j,i*m+j,INF); } if(i-1>=1){ dinic.AddEdge((i-1)*m+j,(i-2)*m+j,INF); } }else///放右边 { dinic.AddEdge((i-1)*m+j,t,w); } } } printf("%d\n",sum-dinic.Maxflow(s,t)); } return 0; }
posted on 2017-07-21 17:02 hnust_accqx 阅读(245) 评论(0) 编辑 收藏 举报