标签:网络流 二分图最大点权独立集
题意:中文题。。
思路:首先根据横纵坐标之和的奇偶转化成二分图,对于( i , j )来说与它冲突的只有(i - 1 , j ) ( i , j - 1 ) ( i + 1 , j ) ( i , j + 1 )4个方格,
奇偶性相反。如果i + j是奇数那么和周围4点连边,那么问题转化求所有点权和 - 该二分图的最小点权覆盖 。我们关注最小点权覆盖
模型,建立超级起点st,超级终点ed, 对于二分图左边的点( i+j为奇数) ,从st向点连一条边,边权为该点的权值,对于二分图右边的
点,从点向ed连一条边,边权为该点的点权。对于二分图之间连的边,边权为inf,所求的最小割就是该二分图的最小点权覆盖,我
们又知道最大流 = 最小割,那么对新建的图求最大流即可。详见代码:
/********************************************************* file name: hdu1569.cpp author : kereo create time: 2015年01月20日 星期二 17时21分28秒 *********************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<set> #include<map> #include<vector> #include<stack> #include<cmath> #include<string> #include<algorithm> using namespace std; typedef long long ll; const int sigma_size=26; const int N=100+50; const int MAXN=2500+50; const int inf=0x3fffffff; const double eps=1e-8; const int mod=100000000+7; #define L(x) (x<<1) #define R(x) (x<<1|1) #define PII pair<int, int> #define mk(x,y) make_pair((x),(y)) int m,n; int edge_cnt,top; int head[MAXN],que[MAXN],s[MAXN],dep[MAXN],cur[MAXN],gap[MAXN]; struct Edge{ int cap,flow,v,next; }edge[MAXN*MAXN]; void init(){ edge_cnt=top=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w){ edge[edge_cnt].v=v; edge[edge_cnt].cap=w; edge[edge_cnt].flow=0; edge[edge_cnt].next=head[u]; head[u]=edge_cnt++; edge[edge_cnt].v=u; edge[edge_cnt].cap=0; edge[edge_cnt].flow=0; edge[edge_cnt].next=head[v]; head[v]=edge_cnt++; } void bfs(int st,int ed){ memset(gap,0,sizeof(gap)); memset(dep,-1,sizeof(dep)); int front=0,rear=0; gap[0]=1; dep[ed]=0; que[rear++]=ed; while(front!=rear){ int u=que[front++]; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(dep[v]!=-1) continue; que[rear++]=v; dep[v]=dep[u]+1; gap[dep[v]]++; } } } int isap(int st,int ed){ bfs(st,ed); memcpy(cur,head,sizeof(head)); int ans=0,u=st; while(dep[st]<n*m+2){ if(u == ed){ int Min=inf,inser; for(int i=0;i<top;i++){ if(edge[s[i]].cap-edge[s[i]].flow<Min){ Min=edge[s[i]].cap-edge[s[i]].flow; inser=i; } } for(int i=0;i<top;i++) edge[s[i]].flow+=Min,edge[s[i]^1].flow-=Min; ans+=Min; top=inser; u=edge[s[top]^1].v; continue; } int flag=0,v; for(int i=cur[u];i!=-1;i=edge[i].next){ v=edge[i].v; if(edge[i].cap-edge[i].flow>0 && dep[v]+1 == dep[u]){ flag=1; cur[u]=i; break; } } if(flag){ s[top++]=cur[u]; u=v; continue; } int d=n*m+2; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(edge[i].cap-edge[i].flow>0 && dep[v]<d) cur[u]=i,d=dep[v]; } gap[dep[u]]--; if(!gap[dep[u]]) return ans; dep[u]=d+1; gap[dep[u]]++; if(u!=st) u=edge[s[--top]^1].v; } return ans; } int main(){ while(~scanf("%d%d",&m,&n)){ init(); int sum=0,st=m*n,ed=m*n+1,w; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ scanf("%d",&w); sum+=w; if((i+j)%2){ addedge(st,i*n+j,w); if(i) addedge(i*n+j,(i-1)*n+j,inf); if(j) addedge(i*n+j,i*n+j-1,inf); if(i!=m-1) addedge(i*n+j,(i+1)*n+j,inf); if(j!=n-1) addedge(i*n+j,i*n+j+1,inf); } else addedge(i*n+j,ed,w); } } printf("%d\n",sum-isap(st,ed)); } return 0; }
标签:网络流 二分图最大点权独立集
原文地址:http://blog.csdn.net/u011645923/article/details/42921817