hdu 1565

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

分析:

定理:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流。可以把所有方格分成两个集合,再构造一个源点和一个汇点,源点向其中一个集合中的所有元素都有一条有向边,权值为元素的权值,另一个集合中的所有元素都分别有一条有向边指向汇点,权值为该元素的权值,两个集合之间也构造有向边,由源点集合的点指向汇点集合的点,权值为无穷大。

  1 #include <cstdio>
  2 #include <cstring>
  3 #define M 405
  4 struct Node
  5 {
  6     int c,pos,next;//流量 边终点
  7 }E[4000];
  8 
  9 int pre[M],head[M];
 10 int q[M],front,rear;
 11 int path[M],matrix[25][25],dir[4][2] = {-1,0,0,-1,1,0,0,1};
 12 int NE,NV;//边的数目,  点的数目
 13 int EK(int s,int t) {
 14     int maxflow = 0;
 15     while(true) {
 16         memset(pre,-1,sizeof(pre));
 17         q[front = rear = 0] = s;
 18         while(front <= rear)
 19         {//BFS
 20             int u = q[front++];
 21             for(int i = head[u]; i != - 1; i = E[i].next ) {
 22                 int v = E[i].pos;
 23                 if(pre[v] == -1 && E[i].c > 0){
 24                     pre[v] = u;
 25                     q[++rear] = v;
 26                     path[v] = i;
 27                 }
 28             }
 29             if(pre[t] != -1)
 30                 break;//达到汇点,跳出BFS
 31         }
 32         if(pre[t] == -1)
 33             break;//无增广路,跳出大循环
 34         int aug = -1;
 35         for(int v = t ; v != s ; v = pre[v]) {
 36             if(aug==-1 || E[path[v]].c<aug){
 37                 aug=E[path[v]].c;
 38                 //寻找最小的delta
 39             }
 40         }
 41         for(int v = t ; v != s ; v = pre[v]) {
 42             E[ path[v] ].c -= aug;
 43             //流量减去delta
 44             E[ path[v]^1 ].c += aug;
 45             //?????????
 46         }
 47         maxflow += aug;
 48     }
 49     return maxflow;
 50 }
 51 void Insert(int u,int v,int c,int cc = 0)
 52 {
 53     E[NE].c = c;    E[NE].pos = v;
 54     E[NE].next = head[u];    head[u] = NE++;
 55     E[NE].c = cc;    E[NE].pos = u;
 56     E[NE].next = head[v];    head[v] = NE++;
 57 }
 58 bool inborder(int r,int c,int n)
 59 {
 60     return r >= 0 && r < n && c >= 0 && c < n;
 61 }
 62 //源点为n*n,汇点为n*n + 1
 63 int main()
 64 {
 65     int n,sum;
 66     while(~scanf("%d",&n))
 67     {
 68         NV = n * n + 2;
 69         for(int i = 0;i < NV;i++)
 70         {
 71             head[i] = -1;
 72         }
 73         sum = 0;
 74         for(int i = 0;i < n;i++)
 75         {
 76             for(int j = 0;j < n;j++)
 77             {
 78                 scanf("%d",&matrix[i][j]);
 79                 sum += matrix[i][j];
 80             }
 81         }
 82         NE = 0;
 83         for(int i = 0;i < n;i++)
 84         {
 85             for(int j = 0;j < n;j++)
 86             {
 87                 if((i + j) % 2 == 0)
 88                 {
 89                     for(int k = 0;k < 4;k++)
 90                     {
 91                         if(inborder(i + dir[k][0],j + dir[k][1],n))
 92                         {
 93                             Insert(i * n + j,(i + dir[k][0]) * n + j + dir[k][1],0xfffffff);
 94                         }
 95                     }
 96                     Insert(n * n,i * n + j,matrix[i][j]);
 97                 }
 98                 else
 99                 {
100                     Insert(i * n + j,n * n + 1,matrix[i][j]);
101                 }
102             }
103         }
104         printf("%d\n",sum - EK(n * n,n * n + 1));
105     }
106     return 0;
107 }

 

posted @ 2013-07-31 09:46  Hogg  阅读(467)  评论(0编辑  收藏  举报