HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题。

HDU1569

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

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

题目思路:

首先我们把所有相邻的格子都连一条边,那么我们的问题就转化成:

这张图上,我们要取得最大的点权(这里的点就相当于带权的格子)集,并且这个点集里的任意两个点之间都没有边(即任意两点不相邻)。

这个即最大点权独立集问题,根据上面的讲解,转化成最小点权覆盖集进行求解。

于是依样画葫芦,先求出所有点权和,记为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 }
时间: 2024-12-25 11:54:35

HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]的相关文章

hdu 1569 方格取数(2) 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5425    Accepted Submission(s): 1695 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的

HDU 1565 1569 方格取数(最大点权独立集)

HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点连向黑点.白点连向汇点,容量都为点容量.然后黑白之间相邻的就连一条容量无限大的边 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using names

【网络流】hdu 1569 方格取数(2)

/* 和1565一样: 总点数的权 - 最小覆盖点集 = 最大独立集 -------------------------------------- void add(int u, int v, int f)加边 { e[ct].u = u; e[ct].v = v; e[ct].f = f; next[ct] = first[u]; first[u] = ct++; e[ct].u = v; e[ct].v = u; e[ct].f = 0; next[ct] = first[v]; first

hdu 1569 方格取数(2)再解

上次我说用STL超时了,而用数组为0ms,其实不然,这个题STL依然不超时,代码如下 #include<map> #include<set> #include<stack> #include<queue> #include<cmath> #include<vector> #include<cstdio> #include<string> #include<cstring> #include<c

hdu 1569 方格取数(2) 网络流 最大点权独立集

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5146    Accepted Submission(s): 1610 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

hdoj 1569 方格取数 【最大点权独立集-&gt;最大流】

题目:hdoj 1569 方格取数 题意:中文题目,就不说题意了. 分类:最大流 |  dp 分析:dp的话应该是个数塔模型,不难做,这里讲转化为图的做法. 这个题目的关键在于转化为一个二分图,来求一个二分图的最大点权独立集,而最大点权独立集 = 点权和 - 最小点权覆盖 最小点权覆盖: 从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小. 最大点权独立集:找到二分图中权值和最大的点集,然后让任意点没有边. 而最小点权覆盖 = 最小割 = 最大流 = sum - 最大

HDU 1569 方格取数(2)

方格取数(2) Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 156964-bit integer IO format: %I64d      Java class name: Main 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Inpu

HDU 1569 方格取数(2)(最小割)

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5256    Accepted Submission(s): 1652 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

HDU 1565 &amp;&amp; HDU 1569 方格取数 (网络流之最小割)

题目地址:HDU 1565       HDU 1569 刚开始接触最小割,就已经感受到了最小割的博大精深... 这建图思路倒是好想..因为好多这种关于不相邻的这种网络流都是基本都是这样建图.但是感觉毫无道理可言...看了题解后才明白这样做的意义. 下面是题解中的说法. 大概是这样分析的,题义是要我们求在一个方格内取出N个点,使得这N个独立的(不相邻)点集的和最大.我们可以将问题转化为最小割来求解.首先,我们将方格进行黑白相间的染色,然后再将任意一种颜色(黑色)作为源点,一种颜色(白色)作为汇点