hdu 1565 最大点权独立集

题意:给你一个m*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。

链接:点我

分析转自:点我

   二分图最小点覆盖和最大独立集都可以转化为最大匹配求解。在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集。

二分图最小点权覆盖

从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。

建模:

原二分图中的边(u,v)替换为容量为INF的有向边(u,v),设立源点s和汇点t,将s和x集合中的点相连,容量为该点的权值;将y中的点同t相连,容量为该点的权值。在新图上求最大流,最大流量即为最小点权覆盖的权值和。

二分图最大点权独立集

在二分图中找到权值和最大的点集,使得它们之间两两没有边。其实它是最小点权覆盖的对偶问题。答案=总权值-最小点覆盖集。具体证明参考胡波涛的论文。

先理理概念:

点覆盖集:无向图G的一个点集,使得该图中所有边都至少有一个端点在该集合内。

最小点权覆盖集:在带点权无向图G中,点权之和最小的覆盖集。

点独立集:无向图G的一个点集,使得任两个在该集合中的点在原图中都不相邻。
最大点权独立集:在带权无向图G中,点权之和最大的独立集。
定理:
1. 最小点权覆盖集=最小割=最大流
2. 最大点权独立集=总权-最小点权覆盖集

思路:

1. 先染色,取一个点染白色,和它相邻的点染黑色
2. 每个白点向它相邻的黑点连一条边,容量为 inf (无穷大)
3. 增加源点S,向每一个白色点连一条边,容量为白点的权
4. 增加汇点T,每个黑点向T连一条边,容量为黑点的权

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 #define MAXN 5555
  6 #define MAXM 222222
  7 #define inf 1<<30
  8
  9 struct Edge{
 10     int v,cap,next;
 11 }edge[MAXM];
 12
 13 int head[MAXN];
 14 int pre[MAXN];
 15 int cur[MAXN];
 16 int level[MAXN];
 17 int gap[MAXN];
 18 int NE,NV,n,vs,vt;
 19 int dir[4][2]={{0,-1},{0,1},{-1,0},{1,0}};
 20 int map[55][55];
 21 bool mark[55][55];
 22
 23 void Insert(int u,int v,int cap,int cc=0){
 24     edge[NE].v=v;edge[NE].cap=cap;
 25     edge[NE].next=head[u];head[u]=NE++;
 26
 27     edge[NE].v=u;edge[NE].cap=cc;
 28     edge[NE].next=head[v];head[v]=NE++;
 29 }
 30
 31 int SAP(int vs,int vt){
 32     memset(pre,-1,sizeof(pre));
 33     memset(level,0,sizeof(level));
 34     memset(gap,0,sizeof(gap));
 35     for(int i=0;i<NV;i++)cur[i]=head[i];
 36     int u=pre[vs]=vs,maxflow=0,aug=-1;
 37     gap[0]=NV;
 38     while(level[vs]<NV){
 39 loop:
 40         for(int &i=cur[u];i!=-1;i=edge[i].next){
 41             int v=edge[i].v;
 42             if(edge[i].cap&&level[u]==level[v]+1){
 43                 aug==-1?aug=edge[i].cap:aug=min(aug,edge[i].cap);
 44                 pre[v]=u;
 45                 u=v;
 46                 if(v==vt){
 47                     maxflow+=aug;
 48                     for(u=pre[u];v!=vs;v=u,u=pre[u]){
 49                         edge[cur[u]].cap-=aug;
 50                         edge[cur[u]^1].cap+=aug;
 51                     }
 52                     aug=-1;
 53                 }
 54                 goto loop;
 55             }
 56         }
 57         int minlevel=NV;
 58         for(int i=head[u];i!=-1;i=edge[i].next){
 59             int v=edge[i].v;
 60             if(edge[i].cap&&minlevel>level[v]){
 61                 cur[u]=i;
 62                 minlevel=level[v];
 63             }
 64         }
 65         gap[level[u]]--;
 66         if(gap[level[u]]==0)break;
 67         level[u]=minlevel+1;
 68         gap[level[u]]++;
 69         u=pre[u];
 70     }
 71     return maxflow;
 72 }
 73
 74 int main(){
 75     while(~scanf("%d",&n)){
 76         vs=0,vt=n*n+1,NE=0,NV=n*n+2;
 77         int sum=0;
 78         memset(head,-1,sizeof(head));
 79         memset(mark,false,sizeof(mark));
 80         for(int i=1;i<=n;i++){
 81             for(int j=1;j<=n;j++){
 82                 scanf("%d",&map[i][j]);
 83                 sum+=map[i][j];
 84             }
 85         }
 86         for(int i=1;i<=n;i++){
 87             for(int j=1;j<=n;j++){
 88                 if(!mark[i][j]){
 89                     Insert(vs,(i-1)*n+j,map[i][j]);
 90                     for(int k=0;k<4;k++){
 91                         int x=i+dir[k][0];
 92                         int y=j+dir[k][1];
 93                         if(x>=1&&x<=n&&y>=1&&y<=n){
 94                             Insert((i-1)*n+j,(x-1)*n+y,inf);
 95                             //建图的时候要小心,每个点只能连一次
 96                             if(!mark[x][y])Insert((x-1)*n+y,vt,map[x][y]);
 97                             mark[x][y]=true;
 98                         }
 99                     }
100                 }
101             }
102         }
103         printf("%d\n",sum-SAP(vs,vt));
104     }
105     return 0;
106 }

2015/5/31

时间: 2024-10-10 02:50:51

hdu 1565 最大点权独立集的相关文章

HDU 1565:最大点权独立集(网络流)

题目要求我们选尽量多的点,同时两两不相邻 可以想到把棋盘按照国际象棋的棋盘样式染色,那同一种颜色的点之间肯定是不相邻的,同时我们也就把图转化为了一个二分图 题目要求也就变成了求这个二分图里的最大点权独立集 最大独立集:包含尽量多顶点的集合,其中任意两点不相邻,所谓的不相邻也就是两点没有连边 最小点覆盖:选取最少的点数,使这些点和所有的边都有关联(把所有的边的覆盖) 最大点权独立集=总权值-最小点权覆盖集 其实不难理解,看看定义就知道了 假设现在已经求出了最小点覆盖,那把这些点去掉,剩下的点肯定是

hdu 4859 最大点权独立集的变形(方格取数的变形)

/*刚开始不会写,最大点权独立集神马都不知道,在潘神的指导下终于做出来,灰常感谢ps: 和方格取数差不多奇偶建图,对于D必割点权为0,对于.必然不割点权为inf.然后和方格取数差不多的建图 .--.||E权值为2,,.||E--D权值为0. 最大点权独立集=sum-最小点权覆盖. */ #include<stdio.h> #include<string.h> #include<queue> using namespace std; #define inf 0x3ffff

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

题目链接:hdu 1565 方格取数(2) 题意: 有一个n*m的方格,每个方格有一个数,现在让你选一些数.使得和最大. 选的数不能有相邻的. 题解: 我们知道对于普通二分图来说,最大独立点集 + 最小点覆盖集 = 总点数,类似的,对于有权的二分图来说,有: 最大点权独立集 + 最小点权覆盖集 = 总点权和, 这个题很明显是要求 最大点权独立集 ,现在 总点权 已知,我们只要求出来 最小点权覆盖集 就好了,我们可以这样建图, 1,对矩阵中的点进行黑白着色(相邻的点颜色不同),从源点向黑色的点连一

HDU 1565:方格取数(1)(最大点权独立集)***

http://acm.hdu.edu.cn/showproblem.php?pid=1565 题意:中文. 思路:一个棋盘,要使得相邻的点不能同时选,问最大和是多少,这个问题就是最大点权独立集. 可以转化为所有的点权 - 最小点权覆盖集(最小割) = 最大点权独立集. 转载两个的定义:这里. 覆盖集(vertex covering set,VCS)是无向图的一个点集,使得该图中所有边都至少有一个端点在该集合内.形式化的定义是点覆盖集为G'VV∈(,)uvE∀∈,满足对于,都有 或成立,即,'uV

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

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

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个格子不能相邻,并且取出的

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 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]

嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. HDU1569: Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,

Educational Codeforces Round 21 F. Card Game(网络流之最大点权独立集)

题目链接:Educational Codeforces Round 21 F. Card Game 题意: 有n个卡片,每个卡片有三个值:p,c,l; 现在让你找一个最小的L,使得满足选出来的卡片l<=L,并且所有卡片的p的和不小于k. 选择卡片时有限制,任意两张卡片的c之和不能为质数. 题解: 和hdu 1565 方格取数(2)一样,都是求最大点权独立集. 不难看出来,这题再多一个二分. 注意的是在构造二部图的时候,按照c值的奇偶性构造. 当c==1时要单独处理,因为如果有多个c==1的卡片,