码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 3657 Game(取数 最小割)经典

时间:2015-07-23 23:55:57      阅读:283      评论:0      收藏:0      [点我收藏+]

标签:算法   图论   最大流   网络流   

Game

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


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
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.
 

Author
onmylove
 

Source
 

题目描述:n*m的矩阵,每个位置都有一个正数,一开始你的分数是0,当你取走一个数字时,你的分数增加那个分数。如果你取完数字后,新出现了2个相邻的都是空的格子,那么你的分数减少2 * ( x & y),x,y是那两个格子的原始数值。

同时有一些附加条件,有一些格子的数字是必须拿走的。

解题:与方格取数差不多,注要多了两个不同的条件。1.取相邻的格子则要减少2*(x&y) 建图时,相邻两个格子之间建边容量为2*(x&y)  2.有K个格子是必须取的,则与必须取的点相连的点S或T的边的容量为INF。这样在求最小割时就不会被割了。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 100010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    pre[sNode] = -1;
    gap[0]=n;
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[i].cap-edg[i].flow){
                Min=edg[i].cap-edg[i].flow;
                inser=i;
            }
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                edg[i].flow+=Min;
                edg[i^1].flow-=Min;  //可回流的边的流量
            }
            ans+=Min;
            u=edg[inser^1].to;
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag){
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
    }
    return ans;
}
int main()
{
    int n,m,k,cost[55][55],flag[55][55];
    int dir[4][2]={0,1,0,-1,1,0,-1,0};
    while(scanf("%d%d%d",&n,&m,&k)>0)
    {
        init();
        int s=n*m,t=n*m+1 , ans=0;
        for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        {
            scanf("%d",&cost[i][j]);
           ans+=cost[i][j];
        }
        int x,y;
        memset(flag,0,sizeof(flag));
        while(k--)
        {
            scanf("%d%d",&x,&y); x--; y--;
            flag[x][y]=1;
        }
        for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        if((i+j)&1)
        {
            addEdg(s , i*m+j , flag[i][j]==0?cost[i][j]:INF);
            for(int e=0; e<4; e++)
             {
                 x=i+dir[e][0];
                 y=j+dir[e][1];
                 if(x>=0&&x<n&&y>=0&&y<m)
                  addEdg(i*m+j, x*m+y,2*(cost[i][j]&cost[x][y]));
             }
        }
        else
            addEdg(i*m+j,t,flag[i][j]==0?cost[i][j]:INF);
            
        ans-=maxFlow_sap(s , t, t+1);
        printf("%d\n",ans);
    }
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU 3657 Game(取数 最小割)经典

标签:算法   图论   最大流   网络流   

原文地址:http://blog.csdn.net/u010372095/article/details/47029295

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!