您的位置:首页 > 其它

hdu 1569 方格取数(2)--最大点权独立集-->最大流

2012-11-05 13:51 239 查看
/*
二分图最小点覆盖和最大独立集都可以转化为最大匹配求解。在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集。

二分图最小点权覆盖
从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。

建模:
原二分图中的边(u,v)替换为容量为INF的有向边(u,v),设立源点s和汇点t,将s和x集合中的点相连,容量为该点的权值;
将y中的点同t相连,容量为该点的权值。在新图上求最大流,最大流量即为最小点权覆盖的权值和。

二分图最大点权独立集
在二分图中找到权值和最大的点集,使得它们之间两两没有边。其实它是最小点权覆盖的对偶问题。答案=总权值-最小点覆盖集。具体证明参考胡波涛的论文。

最大流=最小割=最小点权覆盖集=sum-最大点权独立集

题意:一个m*n的棋盘,每个格子都有一个权值,从中取出某些数,使得任意两个数所在的格子没有公共边,并且所取去出的数和最大。求这个最大的值。
解:
将格子染色成二分图,显然是求二分图的最大点权独立集。将问题转化为二分图最小点权覆盖来求解,最终结果=总权和-最大流。
*/
#include<stdio.h>
#include<string.h>
#define inf 0x7fffffff
struct edge//边
{
int u,v,f,next,b,c;//边的 前节点 后节点 可用流 下条边的编号  原来边上流的上下界
}e[400000];
int head[3000],in[1400],out[1400],m,s,t,ss,tt,yong,indexx[400000],ind;
int n,map[25][25],sum;
void adde(int from,int to,int xia,int shang)//加边
{//加边
e[yong].u=from,e[yong].v=to,e[yong].f=shang-xia,e[yong].b=xia,e[yong].c=shang;
e[yong].next=head[from],head[from]=yong++;
//同时加它的退边
e[yong].u=to,e[yong].v=from,e[yong].f=0,e[yong].b=xia,e[yong].c=shang;
e[yong].next=head[to],head[to]=yong++;
}
int d[3000],num[3000];
int min(int a,int b){return a<b?a:b;}
int sap_gap(int u,int f,int s,int t)//递归sap
{
if(u==t)
return f;
int i,v,mind=t,last=f,cost;
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].v;
int flow=e[i].f;
if(flow>0)//参考模版写的时候把flow写成了f
{
if(d[u]==d[v]+1)
{
cost=sap_gap(v,min(last,flow),s,t);
e[i].f-=cost;
e[i^1].f+=cost;
last-=cost;

if(d[s]>=t+1)
return f-last;

if(last==0)
break;
}
if(d[v]<mind)
mind=d[v];
}
}

if(last==f)
{
--num[d[u]];
if(num[d[u]]==0)
d[s]=t+1;
d[u]=mind+1;
++num[d[u]];
}
return f-last;
}
int max_f(int s,int t)//调用递归sap
{
int f=0;
memset(d,0,sizeof(d));
memset(num,0,sizeof(num));
for(num[s]=t+1;d[s]<t+1;)
f+=sap_gap(s,inf,s,t);
return f;
}
int id(int i,int j)
{
return i*m+j;
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
/*
n*m个点  0--n*m-1   s=n*n  t=s+1
*/
sum=0;
memset(head,-1,sizeof(head));
s=n*m,t=s+1;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&map[i][j]);
sum+=map[i][j];
if((i+j)%2)
{
adde(s,id(i,j),0,map[i][j]);
if(i>0) adde(id(i,j),id(i-1,j),0,inf);
if(i<(n-1)) adde(id(i,j),id(i+1,j),0,inf);
if(j>0) adde(id(i,j),id(i,j-1),0,inf);
if(j<(m-1)) adde(id(i,j),id(i,j+1),0,inf);
}
else
{
adde(id(i,j),t,0,map[i][j]);
}
}
}
printf("%d\n",sum-max_f(s,t));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: