HDU1569 方格取數(2)(最大點權獨立集 + 最小點權覆蓋集 = 總權和)

來源:互聯網
上載者:User

給出一個 N * M 的矩陣,每個格放著一個非負數,要求選出一些數,使他們的和最大,要求是有相鄰邊的格子裡的數不能同時選。

先說,我壓根沒想過這事網路流……因為方格取數(1)是個狀態壓縮……

看了題解,才明白的:

這個題由於資料範圍較大,所以狀態壓縮過不去,需要用網路流,我重複一遍人家的建圖:

我們知道對於普通二分圖來說,最大獨立點集 + 最小點覆蓋集 = 總點數,類似的,對於有權的二分圖來說,有:

最大點權獨立集 + 最小點權覆蓋集 = 總點權和,

這個題很明顯是要求 最大點權獨立集 ,現在 總點權 已知,我們只要求出來 最小點權覆蓋集 就好了,我們可以這樣建圖,

1,對矩陣中的點進行黑白著色(相鄰的點顏色不同),從源點向黑色的點連一條邊,權值為該黑色點的權值,

2,從白色的點向匯點連一條邊,權值為該白色點的權值,

3,然後,對於每一對相鄰的黑白點,從黑點向白點連一條邊,權值為無窮大。

最後求最小割(最大流),即為最小點權覆蓋集。

因為我們求出的最小割集一定是從那些相鄰的黑白點之間的邊(也就是不能用的邊,因為相鄰的數不能同時選)中選出來的,且是最小代價,也就是說從方格中拿掉的數之和盡量小,那麼剩下的數之和一定是最大的。

我只能說,神奇的網路流!!!!Orz!!!!

代碼:

#include<cstdio>#include<cstring>#include<queue>#include<cmath>#define find_min(a,b) a<b?a:busing namespace std;const int N = 2550;const int MAX = 100000;struct Edge{    int s,e,v;    int next;}edge[20*N];int dir[4][2]={-1,0, 1,0, 0,-1, 0,1};int n,m,e_num,head[N],d[N],sp,tp;void AddEdge(int a,int b,int c){    edge[e_num].s=a; edge[e_num].e=b; edge[e_num].v=c;    edge[e_num].next=head[a]; head[a]=e_num++;    edge[e_num].s=b; edge[e_num].e=a; edge[e_num].v=0;    edge[e_num].next=head[b]; head[b]=e_num++;}int judge(int i,int j,int k){    int ii=i+dir[k][0];    int jj=j+dir[k][1];    if(ii>=1 && ii<=n && jj>=1 && jj<=m)return 1;    return 0;}int bfs(){queue <int> q;memset(d,-1,sizeof(d));d[sp]=0;q.push(sp);while(!q.empty()){int cur=q.front();q.pop();for(int i=head[cur];i!=-1;i=edge[i].next){int u=edge[i].e;if(d[u]==-1 && edge[i].v>0){d[u]=d[cur]+1;q.push(u);}}}return d[tp] != -1;}int dfs(int a,int b){int r=0;if(a==tp)return b;for(int i=head[a];i!=-1 && r<b;i=edge[i].next){int u=edge[i].e;if(edge[i].v>0 && d[u]==d[a]+1){int x=find_min(edge[i].v,b-r);x=dfs(u,x);r+=x;edge[i].v-=x;edge[i^1].v+=x;}}if(!r)d[a]=-2;return r;}int dinic(int sp,int tp){int total=0,t;while(bfs()){while(t=dfs(sp,MAX))total+=t;}return total;}int main(){    int i,j,k,a;    while(~scanf("%d%d",&n,&m))    {        int sum=0;        e_num=0;        memset(head,-1,sizeof(head));        sp=0; tp=n*m+1;        for(i=1;i<=n;i++){            for(j=1;j<=m;j++){                scanf("%d",&a);                sum+=a;                int x=(i-1)*m+j;                if((i+j)%2==0){                    AddEdge(sp,x,a);                    for(k=0;k<4;k++){                        if(judge(i,j,k)==1){//不出界                            int y=(i+dir[k][0]-1)*m+(j+dir[k][1]);                            AddEdge(x,y,MAX);//這裡要注意邊的方向,是黑點向白點連邊                        }                    }                }                else{                    AddEdge(x,tp,a);                    for(k=0;k<4;k++){                        if(judge(i,j,k)==1){//不出界                            int y=(i+dir[k][0]-1)*m+(j+dir[k][1]);                            AddEdge(y,x,MAX);//注意邊的方向,和上面的是相反的                        }                    }                }            }        }        int max_flow=dinic(sp,tp);        printf("%d\n",sum-max_flow);    }    return 0;}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.