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

 

你可能感兴趣的:(HDU)