1. 程式人生 > >hdu 1565 方格取數(2)(網絡流之最大點權獨立集)

hdu 1565 方格取數(2)(網絡流之最大點權獨立集)

href aps flow bit 明顯 log sum dir 一個

題目鏈接: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 }
View Code

hdu 1565 方格取數(2)(網絡流之最大點權獨立集)