HDU 3657 Game 网络流--最大独立集

Game

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 668    Accepted Submission(s): 262

Problem Description
onmylove has invented a game on n × m grids. There is one positive integer on each grid. Now you can take the numbers from the grids to make your final score as high as possible. The way to get score is like the following: ● At the beginning, the score is 0; ● If you take a number which equals to x, the score increase x; ● If there appears two neighboring empty grids after you taken the number, then the score should be decreased by 2(x&y). Here x and y are the values used to existed on these two grids. Please pay attention that "neighboring grids" means there exits and only exits one common border between these two grids.
Since onmylove thinks this problem is too easy, he adds one more rule: ● Before you start the game, you are given some positions and the numbers on these positions must be taken away. Can you help onmylove to calculate: what's the highest score onmylove can get in the game?
 
Input
Multiple input cases. For each case, there are three integers n, m, k in a line. n and m describing the size of the grids is n ×m. k means there are k positions of which you must take their numbers. Then following n lines, each contains m numbers, representing the numbers on the n×m grids.Then k lines follow. Each line contains two integers, representing the row and column of one position and you must take the number on this position. Also, the rows and columns are counted start from 1. Limits: 1 ≤ n, m ≤ 50, 0 ≤ k ≤ n × m, the integer in every gird is not more than 1000.
 
Output
For each test case, output the highest score on one line.
 
Sample Input
2 2 1
2 2
2 2
1 1
2 2 1
2 7
4 1
1 1
 
Sample Output
4
9
思路:最大独立集 = ∑V - 最小覆盖集,相对HDU 1565 而言,此题多了一个条件,那就是有些点是必取的,而且相邻点也是可取的,只不过要减去分数2*(x&y),其中y在x之后取,且x和y相邻。构图的时候,构造源点和横纵坐标之和为偶数的点相连,流量为该点的值,如果该点是必选,则添加多这样的一条边,流量则为INF;构造汇点,将横纵坐标之和为奇数的点和汇点相连,流量为该点的值,同样的,若该点必选,则添加流量为INF的边。最后,将所有偶数点和他们的邻接点相连,流量为2*(x&y),其中x是偶数的点,y是他相邻的点。然后直接求出最小割,答案为∑V - 最小割。
 
View Code
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define INF 0x7fffffff
  6 #define MAX 60000
  7 
  8 using namespace std;
  9 
 10 struct node
 11 {
 12     int to,val,next;
 13 };
 14 
 15 node edge[MAX*15];
 16 int head[MAX];
 17 int idx;
 18 
 19 int N,M,K;
 20 int source,sink,pt;
 21 int map[100][100];
 22 
 23 int gap[MAX],dis[MAX];
 24 
 25 void addNode(int from,int to,int val)
 26 {
 27     edge[idx].to = to;
 28     edge[idx].val = val;
 29     edge[idx].next = head[from];
 30     head[from] = idx ++;
 31     edge[idx].to = from;
 32     edge[idx].val = 0;
 33     edge[idx].next = head[to];
 34     head[to] = idx ++;
 35 }
 36 
 37 int dfs(int cur,int cur_val)
 38 {
 39     if(cur == sink)
 40         return cur_val;
 41     int min_dis = pt - 1, temp_val = cur_val;
 42     for(int i=head[cur]; i!=-1; i=edge[i].next)
 43     {
 44         int to = edge[i].to, value = edge[i].val;
 45         if(value > 0)
 46         {
 47             if(dis[to] + 1 == dis[cur])
 48             {
 49                 int val = min(temp_val,edge[i].val);
 50                 val = dfs(to,val);
 51                 temp_val -= val;
 52                 edge[i].val -= val;
 53                 edge[i^1].val += val;
 54                 if(dis[source] >= pt)
 55                     return cur_val - temp_val;
 56                 if(temp_val == 0)
 57                     break;
 58             }
 59             if(min_dis > dis[to])
 60                 min_dis = dis[to];
 61         }
 62     }
 63     if(cur_val == temp_val)
 64     {
 65         --gap[dis[cur]];
 66         if(!gap[dis[cur]])
 67             dis[source] = pt;
 68         dis[cur] = min_dis + 1;
 69         ++gap[dis[cur]];
 70     }
 71     return cur_val - temp_val;
 72 }
 73 
 74 int sap()
 75 {
 76     memset(gap,0,sizeof(gap));
 77     memset(dis,0,sizeof(dis));
 78     gap[source] = pt;
 79     int ret = 0;
 80     while(dis[source] < pt)
 81         ret += dfs(source,INF);
 82     return ret;
 83 }
 84 
 85 int main()
 86 {
 87     while(~scanf("%d%d%d",&N,&M,&K))
 88     {
 89         int sum = 0;
 90         for(int i=1; i<=N; i++)
 91             for(int j=1; j<=M; j++)
 92             {
 93                 scanf("%d",&map[i][j]);
 94                 sum += map[i][j];
 95             }
 96         idx = 0;
 97         memset(head,-1,sizeof(head));
 98         source = 0;
 99         sink = N*M + 1;
100         pt = sink + 1;
101         for(int i=1; i<=K; i++)
102         {
103             int x,y;
104             scanf("%d%d",&x,&y);
105             if((x+y)%2==0)
106                 addNode(source,y+(x-1)*M,INF);
107             else
108                 addNode(y+(x-1)*M,sink,INF);
109         }
110         for(int i=1; i<=N; i++)
111         {
112             for(int j=1; j<=M; j++)
113             {
114                 int temp = j+(i-1)*M;
115                 if((i+j)%2 == 0)
116                     addNode(source,temp,map[i][j]);
117                 else
118                     addNode(temp,sink,map[i][j]);
119             }
120         }
121         for(int i=1; i<=N; i++)
122         {
123             for(int j=1; j<=M; j++)
124             {
125                 if((i+j)%2==0)
126                 {
127                     int temp = j+(i-1)*M;
128                     if(j-1>0)
129                         addNode(temp,temp-1,2*(map[i][j]&map[i][j-1]));
130                     if(j+1<=M)
131                         addNode(temp,temp+1,2*(map[i][j]&map[i][j+1]));
132                     if(i-1>0)
133                         addNode(temp,temp-M,2*(map[i][j]&map[i-1][j]));
134                     if(i+1<=N)
135                         addNode(temp,temp+M,2*(map[i][j]&map[i+1][j]));
136                 }
137             }
138         }
139         int ans = sap();
140         printf("%d\n",sum-ans);
141     }
142     return 0;
143 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值