hdu1569——方格取數(2)
阿新 • • 發佈:2018-11-08
給你一個mn的格子的棋盤,每個格子裡面有一個非負數。
從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取數所在的2個格子不能相鄰,並且取出的數的和最大。
Input
包括多個測試例項,每個測試例項包括2整數m,n和mn個非負數(m<=50,n<=50)
Output
對於每個測試例項,輸出可能取得的最大的和
Sample Input
3 3
75 15 21
75 15 28
34 70 5
Sample Output
188
第一次做根本沒想到是網路流,這次搜網絡流的題目找到了這道題,從一個矩陣中找出若干個不相鄰的數使得權值和最大
咋一看是dp啥的,但其實這是一個二分圖的問題,可以觀察看出x座標和y座標之和的奇偶性可以來判斷是否相鄰,所以就可以將矩陣中的數分為兩半,就是一個二分圖了,所以要求的就是這個二分圖的最大點權獨立集,然後由
最大流=最小割=最小點權覆蓋=點權和-最大點權獨立集
直接模板求出最大流即可
程式碼:
#include <cstdio> #include <algorithm> #include <cstring> #include <queue> //#define _clr(x,a) memset(x,a,sizeof(x)) using namespace std; const int N=1e5+10; const int M=1e5+50; const int INF=0x3f3f3f3f; int n,m; int x; int head[N]; int tot; int dep[N]; int s,t; int cur[N]; struct Edge{ int u,v,w,next; }edge[M]; void init(){ tot=0; memset(head,-1,sizeof(head)); } void addEdge(int u,int v,int w){ edge[tot]=Edge{u,v,w,head[u]}; head[u]=tot++; edge[tot]=Edge{v,u,0,head[v]}; head[v]=tot++; } bool bfs(){ queue<int> q; memset(dep,0,sizeof(dep)); dep[s]=1; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; int w=edge[i].w; if(w>0 && dep[v]==0){ dep[v]=dep[u]+1; q.push(v); } } } return dep[t]!=0; } int dfs(int u,int flow){ if(u==t){ return flow; } for(int &i=cur[u];i!=-1;i=edge[i].next){ int v=edge[i].v; int w=edge[i].w; if(dep[v]==dep[u]+1 && w!=0){ int dis=dfs(v,min(w,flow)); if(dis>0){ edge[i].w-=dis; edge[i^1].w+=dis; return dis; } } } return 0; } int dinic(){ int ans=0; while(bfs()){ for(int i=0;i<=t;i++){ cur[i]=head[i]; } while(int d=dfs(s,INF)){ ans+=d; } } return ans; } int dx[]={-1,1,0,0}; int dy[]={0,0,-1,1}; int main(void){ while(~scanf("%d%d",&n,&m)){ init(); s=n*m; t=n*m+1; int sum=0; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%d",&x); if((i+j)%2){ addEdge(s,i*m+j,x); if(i>0){ addEdge(i*m+j,(i-1)*m+j,INF); } if(i<n-1){ addEdge(i*m+j,(i+1)*m+j,INF); } if(j>0){ addEdge(i*m+j,i*m+j-1,INF); } if(j<m-1){ addEdge(i*m+j,i*m+j+1,INF); } } else{ addEdge(i*m+j,t,x); } sum+=x; } } int ans=dinic(); printf("%d\n",sum-ans); } return 0; }