HDU 1569 - 方格取数 - [最大点权独立集与最小点权覆盖集]
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 1569 - 方格取数 - [最大点权独立集与最小点权覆盖集]相关的知识,希望对你有一定的参考价值。
嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Problem Description
给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的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
题目思路:
首先我们把所有相邻的格子都连一条边,那么我们的问题就转化成:
这张图上,我们要取得最大的点权(这里的点就相当于带权的格子)集,并且这个点集里的任意两个点之间都没有边(即任意两点不相邻)。
这个即最大点权独立集问题,根据上面的讲解,转化成最小点权覆盖集进行求解。
于是依样画葫芦,先求出所有点权和,记为sum(Wv);
每个相邻的两个格子建边,cap设为INF,方向为从(i+j)是奇数的点到(i+j)是偶数的点;
建立超级源点s,连到所有(i+j)为奇数的点,方向为s出发,cap设为点权;
建立超级汇点t,连到所有(i+j)为偶数的点,方向为到达t,cap设为点权;
这样的话,这个图中,m行n列的方格阵,|V| = mn+2,|E| = m(n-1)+n(m-1) = 2mn-m-n;
我们做最大流求s-t最小割cut.w,便可以得到答案为sum(Wv) - cut.w。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #define MAX 53*53 6 #define INF 0x3f3f3f3f 7 using namespace std; 8 int m,n,map[53][53],sum; 9 int d[4][2]={{0,+1},{+1,0},{0,-1},{-1,0}}; 10 struct Edge{ 11 int u,v,c,f; 12 }; 13 struct Dinic 14 { 15 int s,t; 16 vector<Edge> E; 17 vector<int> G[MAX]; 18 bool vis[MAX]; 19 int lev[MAX]; 20 int cur[MAX]; 21 void init(int l,int r) 22 { 23 E.clear(); 24 for(int i=l;i<=r;i++) G[i].clear(); 25 } 26 void addedge(int from,int to,int cap) 27 { 28 E.push_back((Edge){from,to,cap,0}); 29 E.push_back((Edge){to,from,0,0}); 30 G[from].push_back(E.size()-2); 31 G[to].push_back(E.size()-1); 32 } 33 bool bfs() 34 { 35 memset(vis,0,sizeof(vis)); 36 queue<int> q; 37 q.push(s); 38 lev[s]=0; 39 vis[s]=1; 40 while(!q.empty()) 41 { 42 int now=q.front(); q.pop(); 43 for(int i=0,_size=G[now].size();i<_size;i++) 44 { 45 Edge edge=E[G[now][i]]; 46 int nex=edge.v; 47 if(!vis[nex] && edge.c>edge.f) 48 { 49 lev[nex]=lev[now]+1; 50 q.push(nex); 51 vis[nex]=1; 52 } 53 } 54 } 55 return vis[t]; 56 } 57 int dfs(int now,int aug) 58 { 59 if(now==t || aug==0) return aug; 60 int flow=0,f; 61 for(int& i=cur[now],_size=G[now].size();i<_size;i++) 62 { 63 Edge& edge=E[G[now][i]]; 64 int nex=edge.v; 65 if(lev[now]+1 == lev[nex] && (f=dfs(nex,min(aug,edge.c-edge.f)))>0) 66 { 67 edge.f+=f; 68 E[G[now][i]^1].f-=f; 69 flow+=f; 70 aug-=f; 71 if(!aug) break; 72 } 73 } 74 return flow; 75 } 76 int maxflow() 77 { 78 int flow=0; 79 while(bfs()) 80 { 81 memset(cur,0,sizeof(cur)); 82 flow+=dfs(s,INF); 83 } 84 return flow; 85 } 86 }dinic; 87 int inmap(int i,int j) 88 { 89 if(1<=i && i<=m && 1<=j && j<=n) return (i-1)*n+j; 90 else return 0; 91 } 92 int main() 93 { 94 while(scanf("%d%d",&m,&n)!=EOF)//m行n列 95 { 96 dinic.init(0,m*n+1); 97 sum=0; 98 dinic.s=0, dinic.t=m*n+1; 99 for(int i=1;i<=m;i++) 100 { 101 for(int j=1;j<=n;j++) 102 { 103 scanf("%d",&map[i][j]); 104 sum+=map[i][j]; 105 int id=(i-1)*n+j; 106 if((i+j)%2) 107 { 108 for(int k=0,_id;k<4;k++) if(_id=inmap(i+d[k][0],j+d[k][1])) dinic.addedge(id,_id,INF); 109 dinic.addedge(dinic.s,id,map[i][j]); 110 } 111 else dinic.addedge(id,dinic.t,map[i][j]); 112 } 113 } 114 printf("%d\\n",sum-dinic.maxflow()); 115 } 116 }
以上是关于HDU 1569 - 方格取数 - [最大点权独立集与最小点权覆盖集]的主要内容,如果未能解决你的问题,请参考以下文章
HDU 1569 - 方格取数 - [最大点权独立集与最小点权覆盖集]