您的位置:首页 > 其它

hdu1569 方格取数(2) 最大点权独立集=总权和-最小点权覆盖集 (最小点权覆盖集=最小割=最大流)

2017-07-21 17:02 399 查看
/**
转自: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
;
bool vis
;
int d
;
int cur
;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: