HDU3657 Game(最小割)

来源:互联网 发布:大淘客cms网站logo 编辑:程序博客网 时间:2024/05/11 20:44

Game

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


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 12 22 21 12 2 12 74 11 1
 

Sample Output
49
Hint
As to the second case in Sample Input, onmylove gan get the highest score when calulating like this:2 + 7 + 4 - 2 × (2&4) - 2 × (2&7) = 13 - 2 × 0 - 2 × 2 = 9.
 
题意:有n*m个格子,每个格子都有一个价值,选择一个格子可以获得它的价值,如果选择两个相邻的格子那么除了获得两个格子的价值,还要减去这两个格子&运算的结果的两倍。现在有k个格子必选,求能获得的最大价值。
思路:首先得看的出它是一道最小割的题(并没有看出- -),然后假设所有的格子的价值都已经获得,在这样的情况下,要么去掉某些格子,要么保留相邻的格子但要减去他们&运算的两倍,这就是关系,根据关系就可以建图。
首先额外添加源点S,汇点T,S点连向横坐标和纵坐标加起来是偶数的点,权值是点值,横坐标和纵坐标的和是奇数的点连向T,权值是点值,其中必选的点的边的权值是无穷大,这样就不会被割。相邻的点之间连线权值为2*(x&y)。这样求最小割就是求舍弃某些点的值、保留两个点的值的代价,这两个选择的和最小。
#include <bits/stdc++.h>using namespace std;#define maxn 3200#define maxm 50010#define inf 1<<30int head[maxm], Layer[maxn], que[maxn];int tot, n, m, S, T;int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};int Map[55][55], p[55][55];bool vis[55][55];struct node{    int to, next, cap;}G[maxm];void add(int u, int v, int cap){    G[tot].to = v, G[tot].cap = cap, G[tot].next = head[u], head[u] = tot++;    G[tot].to = u, G[tot].cap = 0, G[tot].next = head[v], head[v] = tot++;}bool bfs(){    int rear = 0;    memset(Layer , -1, sizeof Layer);    que[rear++] = S;    Layer[S] = 0;    for(int i = 0;i < rear;i++){        int u = que[i];        for(int j = head[u];j != -1;j = G[j].next){            int v= G[j].to;            if(G[j].cap>0&&Layer[v]==-1){                Layer[v] = Layer[u] + 1;                que[rear++] = v;                if(v == T) return 1;            }        }    }    return 0;}int dfs(int u, int maxflow){    if(u == T||maxflow == 0) return maxflow;    int sum = 0;    for(int i = head[u];i != -1;i = G[i].next){        int v = G[i].to;        if(G[i].cap>0&&Layer[v]==Layer[u]+1){            int t = dfs(v, min(maxflow, G[i].cap));            G[i].cap -= t;            G[i^1].cap += t;            sum += t;            maxflow -= t;        }    }    return sum;}int dinic(){    int ans = 0;    while(bfs()){        ans += dfs(S, inf);    }    return ans;}int main(){    int i, j, k, sum, cnt, l;    while(~scanf("%d %d %d", &n, &m, &k)){        memset(head, -1, sizeof head);        memset(vis, 0, sizeof vis);        tot = sum = 0;        cnt = 1;        for(i = 1;i <= n;i++){            for(j = 1;j <= m;j++){                scanf("%d", &Map[i][j]);                sum += Map[i][j];                p[i][j] = cnt++;            }        }        S = 0, T = n*m+1;        int x, y;        for(i = 0;i < k;i++){            scanf("%d %d", &x, &y);            if((x+y)%2==0) add(S, p[x][y], inf);            else add(p[x][y], T, inf);            vis[x][y] = 1;        }        for(i = 1;i <= n;i++){            for(j = 1;j <= m;j++){                if((i+j)%2==0){                    for(l = 0;l < 4;l++){                        x = i + dx[l];                        y = j + dy[l];                        if(x>=1&&x<=n&&y>=1&&y<=m)                            add(p[i][j], p[x][y], 2*(Map[i][j]&Map[x][y]));                    }                    if(!vis[i][j]) add(S, p[i][j], Map[i][j]);                }else if(!vis[i][j]) add(p[i][j], T, Map[i][j]);            }        }        printf("%d\n", sum-dinic());    }}

0 0
原创粉丝点击