方格取數(2)(最大點權獨立集)
阿新 • • 發佈:2019-01-09
Problem Description
給你一個m*n的格子的棋盤,每個格子裡面有一個非負數。
從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取數所在的2個格子不能相鄰,並且取出的數的和最大。
Input 包括多個測試例項,每個測試例項包括2整數m,n和m*n個非負數(m<=50,n<=50)
Output 對於每個測試例項,輸出可能取得的最大的和
Sample Input 3 3 75 15 21 75 15 28 34 70 5
Sample Output
188
從中取出若干個數,使得任意的兩個數所在的格子沒有公共邊,就是說所取數所在的2個格子不能相鄰,並且取出的數的和最大。
Input 包括多個測試例項,每個測試例項包括2整數m,n和m*n個非負數(m<=50,n<=50)
Output 對於每個測試例項,輸出可能取得的最大的和
Sample Input 3 3 75 15 21 75 15 28 34 70 5
Sample Output
心得:關於最大點權獨立集和最小點權覆蓋問題,關鍵是把所有的點分成兩個集合,集合內部的點互不相關
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #include<queue> using namespace std; #define INF 0x3f3f3f3f #define min(a,b) (a<b ? a:b) const int maxn=5000+10; struct Edge{ int from,to,cap,flow; Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow) {} }; int n,m,s,t; vector<Edge> edges; vector<int> G[maxn]; bool vis[maxn]; int d[maxn],cur[maxn]; void AddEdge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool bfs() { memset(vis,0,sizeof(vis)); queue<int> Q; Q.push(s); vis[s]=1; d[s]=0; while(!Q.empty()) { int x=Q.front(); Q.pop(); for(int i=0;i<G[x].size();i++) { Edge& e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow) { vis[e.to]=1; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int dfs(int x,int a) { if(x==t||a==0) return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++) { Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0) { e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int Maxflow() { int flow=0; while(bfs()) { memset(cur,0,sizeof(cur)); flow+=dfs(s,INF); } return flow; } int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { int i,j,k=1,x,sum=0,flag; s=0; t=n*m+1; edges.clear(); for(i=0;i<=t;i++) G[i].clear(); for(i=0;i<n;i++) { if(i&1) flag=0; else flag=1; for(j=0;j<m;j++,k++) { scanf("%d",&x); sum+=x; if((j&1)==flag) AddEdge(k,t,x); else { AddEdge(s,k,x); if(k-m>0) AddEdge(k,k-m,INF); if(k+m<=n*m) AddEdge(k,k+m,INF); if(k%m!=1) AddEdge(k,k-1,INF); if(k%m!=0) AddEdge(k,k+1,INF); } } } printf("%d\n",sum-Maxflow()); } return 0; }