HDU1565 方格取数(1) 网络流

http://acm.hdu.edu.cn/showproblem.php?pid=1565

题意:

  给出N*N的格子,每个格子里都有数字,问你怎么样取数字能使其和最大,前提是取出来的格子不能两两相邻。

 

坑爹:

  一开始以为不是选奇数位置就是偶数位置就能解出来的水题,仔细看了下题意发现天真了。。。

 

解法:

  这道题可以用网络流的最小割来做

  最大流 = 最小割 = 最小点权覆盖集 = sum - 最大点权独立集

先设置一个源点(0)和一个汇点( n*n+1),一开始初始化的时候把源点到所有 (i+j)%2 ==1的格子全部给个值,

然后初始化把汇点到所有 (i+j) %2 == 0的格子也给个值,值就是这个格子数字。还有,我在记录这些值的二维数组temp[i][j]

中的下标 i 和 j 是代表第几个格子,比如说:

3

987

654

321

这样的数据的话,初始化源点的格子分别为9,7,5,3,1,但是9是第1个,3是第7个(一行一行数)。

然后还有一个步骤就是将所有的点与他附近的点的temp值都为INF(最大值),这样就形成了一个图,

问题就转换为花费最少的流量将这个图的源点和汇点切断(最小割),剩下的值就能达到最大了。

 

View Code
  1 #include<iostream>
  2 #include<queue>
  3 using namespace std;
  4 
  5 const int maxn = 20 + 10;
  6 const int INF = 0x3fffffff;
  7 int map[maxn][maxn];
  8 int point[4][2] = {0,1,0,-1,1,0,-1,0};
  9 int temp[maxn*maxn][maxn*maxn];
 10 int n;
 11 
 12 bool judge(int x,int y) // 判断是否越界
 13 {
 14     if(x>0 && x<=n && y>0 && y<=n)
 15     {
 16         return 1;
 17     }
 18     return 0;
 19 }
 20 
 21 int BFS(int s,int t)
 22 {
 23     int flow = 0;
 24     while(1)
 25     {
 26         int pre[maxn*maxn];
 27         memset(pre,-1,sizeof(pre));
 28         int i;
 29         int min = INF;//找出最小流量
 30         queue<int> Q; //放进去的代表是第几个
 31         Q.push(s);
 32         int begin;
 33         while(!Q.empty())
 34         {
 35             begin = Q.front();
 36             Q.pop();
 37             for(i=1; i<=n*n+1; i++)
 38             {
 39                 if(temp[begin][i] > 0 && pre[i] == -1)
 40                 {
 41                     Q.push(i);
 42                     if(temp[begin][i] < min)
 43                     {
 44                         min = temp[begin][i];
 45                     }
 46                     pre[i] = begin;
 47                 }
 48             }
 49             if(pre[t] != -1)
 50             {
 51                 break;
 52             }
 53         }
 54         
 55         int u = t;
 56         if(pre[u] <= 0)
 57         {
 58             break;
 59         }
 60 
 61         while(u != s)  // 减去流量
 62         {
 63             temp[pre[u]][u] -= min;
 64             temp[u][pre[u]] += min;
 65             u = pre[u];
 66         }
 67         flow += min;
 68     }
 69     return flow;
 70 }
 71 
 72 
 73 int main()
 74 {
 75     while(cin>>n)
 76     {
 77         memset(map,0,sizeof(map));
 78         memset(temp,0,sizeof(temp));
 79         int i;
 80         int j;
 81         int sum = 0;
 82         for(i=1; i<=n; i++)
 83         {
 84             for(j=1; j<=n; j++)
 85             {
 86                 cin>>map[i][j];
 87                 sum += map[i][j];
 88             }
 89         }
 90 
 91         // 0作为源点  n*n+1作为汇点
 92         for(i=1; i<=n; i++)
 93         {
 94             for(j=1; j<=n; j++)
 95             {
 96                 if( (i+j)%2 == 0 )
 97                 {
 98                     temp[0][(i-1)*n+j] = map[i][j];
 99                 }
100                 else
101                 {
102                     temp[(i-1)*n+j][n*n+1] = map[i][j];
103                 }
104             }
105         }
106         
107         // 将与源点相连的点的相邻的值附上INF
108         for(i=1; i<=n; i++)
109         {
110             for(j=1; j<=n; j++)
111             {
112                 for(int k=0; k<4; k++)
113                 {
114                     int x = i + point[k][0];
115                     int y = j + point[k][1];
116                     if( judge(x,y) && (i+j) % 2 == 0 )
117                     {
118                         temp[(i-1)*n+j][(x-1)*n+y] = INF;   // (i-1)*n+j 代表的是第几个
119                                                             // 123
120                                                             // 456
121                                                             // 789   的话7的话就是第7个
122                     }
123                 }
124             }
125         }
126         int s = 0;//源点
127         int t = n*n+1;//汇点
128 
129         cout<<sum-BFS(s,t)<<endl;
130     }
131     return 0;
132 }

 

 

 

转载于:https://www.cnblogs.com/pcpcpc/archive/2013/04/13/3019326.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值