题目链接:hdu 1565 方格取数(2)
题意:
有一个n*m的方格,每个方格有一个数,现在让你选一些数。使得和最大。
选的数不能有相邻的。
题解:
我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有:
最大点权独立集 + 最小点权覆盖集 = 总点权和,
这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图,
1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一条边,权值为该黑色点的权值,
2,从白色的点向汇点连一条边,权值为该白色点的权值,
3,然后,对于每一对相邻的黑白点,从黑点向白点连一条边,权值为无穷大。
最后求最小割(最大流),即为最小点权覆盖集。
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;i++) 3 using namespace std; 4 5 const int N=2550,inf=~0U>>2,M=1e6+7; 6 struct edge{int t,f;edge*nxt,*pair;}*g[N],*d[N],pool[M],*cur=pool; 7 struct ISAP{ 8 int n,m,i,S,T,h[N],gap[N],maxflow; 9 void init(int ss,int tt){for(S=ss,T=tt,cur=pool,i=1;i<=T;i++)g[i]=d[i]=NULL,h[i]=gap[i]=0;} 10 void add(int s,int t,int f){ 11 edge*p=cur++;p->t=t,p->f=f,p->nxt=g[s],g[s]=p; 12 p=cur++,p->t=s,p->f=0,p->nxt=g[t],g[t]=p; 13 g[s]->pair=g[t],g[t]->pair=g[s]; 14 } 15 int sap(int v,int flow){ 16 if(v==T)return flow; 17 int rec=0; 18 for(edge*p=d[v];p;p=p->nxt)if(h[v]==h[p->t]+1&&p->f){ 19 int ret=sap(p->t,min(flow-rec,p->f)); 20 p->f-=ret;p->pair->f+=ret;d[v]=p; 21 if((rec+=ret)==flow)return flow; 22 } 23 if(!(--gap[h[v]]))h[S]=T; 24 gap[++h[v]]++;d[v]=g[v]; 25 return rec; 26 } 27 int get_ans(){ 28 for(gap[maxflow=0]=T,i=1;i<=T;i++)d[i]=g[i]; 29 while(h[S]<T)maxflow+=sap(S,inf); 30 return maxflow; 31 } 32 }G; 33 34 int n,m,mp[55][55],sum,dir[][2]={1,0,-1,0,0,1,0,-1}; 35 36 int main() 37 { 38 while(~scanf("%d%d",&n,&m)) 39 { 40 G.init(n*m+1,n*m+2);sum=0; 41 F(i,1,n)F(j,1,m)scanf("%d",&mp[i][j]),sum+=mp[i][j]; 42 F(i,1,n)F(j,1,m) 43 { 44 if((i+j)&1){G.add((i-1)*m+j,G.T,mp[i][j]);continue;} 45 G.add(G.S,(i-1)*m+j,mp[i][j]); 46 F(ii,0,3) 47 { 48 int x=i+dir[ii][0],y=j+dir[ii][1]; 49 if(x<1||x>n||y<1||y>m)continue; 50 G.add((i-1)*m+j,(x-1)*m+y,inf); 51 } 52 } 53 printf("%d\n",sum-G.get_ans()); 54 } 55 return 0; 56 }
原文:http://www.cnblogs.com/bin-gege/p/6914656.html