您的位置:首页 > 理论基础 > 计算机网络

线性规划与网络流24题 09方格取数问题

2011-10-08 20:47 323 查看
最大独立团的最小割解法。。。。。

最小割在实际问题中不容易分析出来。。。多加强这方面的分析能力。。。。


【问题分析】

二分图点权最大独立集,转化为最小割模型,从而用最大流解决。

【建模方法】

首先把棋盘黑白染色,使相邻格子颜色不同,所有黑色格子看做二分图X集合中顶点,白色格子看做Y集合顶点,建立附加源S汇T。

1、从S向X集合中每个顶点连接一条容量为格子中数值的有向边。

2、从Y集合中每个顶点向T连接一条容量为格子中数值的有向边。

3、相邻黑白格子Xi,Yj之间从Xi向Yj连接一条容量为无穷大的有向边。

求出网络最大流,要求的结果就是所有格子中数值之和减去最大流量。

【建模分析】

这是一个二分图最大点权独立集问题,就是找出图中一些点,使得这些点之间没有边相连,这些点的权值之和最大。独立集与覆盖集是互补的,求最大点权独立集可以转化为求最小点权覆盖集(最小点权支配集)。最小点权覆盖集问题可以转化为最小割问题解决。结论:最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流。

对于一个网络,除去冗余点(不存在一条ST路径经过的点),每个顶点都在一个从S到T的路径上。割的性质就是不存在从S到T的路径,简单割可以认为割边关联的非ST节点为割点,而在二分图网络流模型中每个点必关联到一个割点(否则一定还有增广路,当前割不成立),所以一个割集对应了一个覆盖集(支配集)。最小点权覆盖集就是最小简单割,求最小简单割的建模方法就是把XY集合之间的变容量设为无穷大,此时的最小割就是最小简单割了。

有关二分图最大点权独立集问题,更多讨论见《最小割模型在信息学竞赛中的应用》作者胡伯涛。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 1<<30
#define N 1000000
#define M 50000
#define cc(m,v) memset(m,v,sizeof(m))
struct node{
int u,v,f,next;
}edge
;
int head[M],p,lev[M],cur[M];
int que
;
void ainit(){
p=0,cc(head,-1);
}
void addedge(int u,int v,int f){
edge[p].u=u,edge[p].v=v,edge[p].f=f,edge[p].next=head[u],head[u]=p++;
edge[p].u=v,edge[p].v=u,edge[p].f=0,edge[p].next=head[v],head[v]=p++;
}
bool bfs(int s,int t){
int i,u,v,qin=0,qout=0;
cc(lev,0),lev[s]=1,que[qin++]=s;
while(qout!=qin){
u=que[qout++];
for(i=head[u];i!=-1;i=edge[i].next)
if(edge[i].f>0 && !lev[v=edge[i].v]){
lev[v]=lev[u]+1,que[qin++]=v;
if(v==t) return 1;
}
}
return 0;
}
int dinic(int s,int t){
int i,f,k,qin,u;
int flow=0;
while(bfs(s,t)){
memcpy(cur,head,sizeof(head));
u=s,qin=0;
while(1){
if(u==t){
for(k=0,f=inf;k<qin;k++)
if(edge[que[k]].f<f) f=edge[que[i=k]].f;
for(k=0;k<qin;k++)
edge[que[k]].f-=f,edge[que[k]^1].f+=f;
flow+=f,u=edge[que[qin=i]].u;
}
for(i=cur[u];cur[u]!=-1;i=cur[u]=edge[cur[u]].next)
if(edge[i].f>0 && lev[u]+1==lev[edge[i].v]) break;
if(cur[u]!=-1)
que[qin++]=cur[u],u=edge[cur[u]].v;
else{
if(qin==0) break;
lev[u]=-1,u=edge[que[--qin]].u;
}
}
}
return flow;
}
int main(){
int n,m,i,j,s,t,u,sum,cnt;
while(scanf("%d%d",&m,&n)!=-1){
ainit();
s=0,t=n*m+1,sum=0,cnt=0;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++){
scanf("%d",&u);
sum+=u;
if((i+j)&1){
addedge(++cnt,t,u);
}else{
addedge(s,++cnt,u);
if(j>1) addedge(cnt,cnt-1,inf);
if(i>1) addedge(cnt,cnt-n,inf);
if(i<m) addedge(cnt,cnt+n,inf);
if(j<n) addedge(cnt,cnt+1,inf);
}
}
int ans=sum-dinic(s,t);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: