hdu 3820 Golden Eggs【最大流Dinic-------最小割】好题

来源:互联网 发布:淘宝旺旺名字怎么改 编辑:程序博客网 时间:2024/05/14 11:27

Golden Eggs

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 559    Accepted Submission(s): 326

Problem Description

There is a grid with N rows and M columns. In each cell you can choose to put a golden or silver egg in it, or just leave it empty. If you put an egg in the cell, you will get some points which depends on the color of the egg. But for every pair of adjacent eggs with the same color, you lose G points if there are golden and lose S points otherwise. Two eggs are adjacent if and only if there are in the two cells which share an edge. Try to make your points as high as possible.

Input

The first line contains an integer T indicating the number of test cases.
There are four integers N, M, G and S in the first line of each test case. Then 2*N lines follows, each line contains M integers. The j-th integer of the i-th line Aij indicates the points you will get if there is a golden egg in the cell(i,j). The j-th integer of the (i+N)-th line Bij indicates the points you will get if there is a silver egg in the cell(i,j).

Technical Specification
1. 1 <= T <= 20
2. 1 <= N,M <= 50
3. 1 <= G,S <= 10000
4. 1 <= Aij,Bij <= 10000

Output

For each test case, output the case number first and then output the highest points in a line.

Sample Input

2

2 2 100 100

1 1

5 1

1 4

1 1

1 4 85 95

100 100 10 10

10 10 100 100

Sample Output

Case 1: 9

Case 2: 225

Author

hanshuai

Source

The 6th Central China Invitational Programming Contest and 9th Wuhan University Programming Contest Final


题目大意:跟方格取数那个最大流的题很像,不过升级了一下:

有n*m这么大个矩阵,从中我们可以放置金,也可以放置银,放置每种物品的价值会给你,相邻的两个小方格子如果是同一种物品,如果是两金,需要去掉g值,如果是两银 ,需要去掉s值。

输入分析:t组数据,第一行输入四个元素,表示n,m,g,s、

接下来两个n*m的矩阵,第一个表示这个位子上放置金的价值,第二个表示这个位子上放置银的价值。


思路:


1、首先我们明确,对于当前位子上放置金还是银有一个限制,根据最小割最大流定理,我们不难将图初建成这样:


其中建图规则:

①从SS到放置金的节点期权制为放置金所能够获得的值

②将每个节点一分为二,一个表示放置金节点,一个表示放置银节点,其间权值为INF。

③将放置银节点连入汇点T,其权值为放置银获得的值。

如果按照如此进行一次最大流的计算,那么获得的值就是最小割,其实也就可以理解为最小抛弃值,然后计算sum(sum表示两个矩阵加一起的值),用sum-maxflow得到值tmp。那么tmp就是没有在任何限制条件下,只考虑一个点放置金还是放置银的最大获得值。


2、那么当我们有两金和两银的限制的时候,我们不难想到二分图,相邻的两个点属于两个不同的集合,如下面一个3*3的图,其中数字一样的表示在一个集合中:

121212121很明显,其中1和1之间没有交集,形成一个二分图的模型。


3、那么我们将带有限制的图建立成这样:


其中建图规则:

①从SS到集合1中的点,其权值为放置金的值。(集合2相反)

②将每个节点一分为二,一个表示放置金节点,一个表示放置银节点,其间权值为INF。

③将集合1中的点拆分出来的点连入T中,其权值为放置银的价值。(集合2相反)

④将不同集合中的两个金和两个银相连,其权值为g和s。


4、那么这样建图跑出来的最大流就是最小割,也就是将所有值都要的情况下的最小抛弃值,那么ans=sum-maxflow、


Ac代码:


#include<stdio.h>#include<string.h>#include<queue>#include<iostream>using namespace std;#define INF 0x3f3f3f3fstruct node{    int from;    int to;    int next;    int w;}e[1515151];int a[500][500];int aa[500][500];int divv[500*500];int cur[500*500];int head[500*500];int fx[4]={0,0,1,-1};int fy[4]={1,-1,0,0};int n,m,g,sl,ss,tt,cont;void add(int from,int to,int w){    e[cont].to=to;    e[cont].w=w;    e[cont].next=head[from];    head[from]=cont++;}void getmap(){    ss=n*m*2+1;    tt=ss+1;    cont=0;    memset(head,-1,sizeof(head));    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            add((i-1)*m+j,n*m+(i-1)*m+j,INF);            add(n*m+(i-1)*m+j,(i-1)*m+j,0);            if((i+j)%2==0)            {                add(ss,(i-1)*m+j,a[i][j]);                add((i-1)*m+j,ss,0);                add(n*m+(i-1)*m+j,tt,aa[i][j]);                add(tt,n*m+(i-1)*m+j,0);            }            else            {                add(ss,(i-1)*m+j,aa[i][j]);                add((i-1)*m+j,ss,0);                add(n*m+(i-1)*m+j,tt,a[i][j]);                add(tt,n*m+(i-1)*m+j,0);            }        }    }    for(int i=1;i<=n;i++)    {        for(int j=1;j<=m;j++)        {            for(int k=0;k<4;k++)            {                int xx=i+fx[k];                int yy=j+fy[k];                if(xx>=1&&xx<=n&&yy>=1&&yy<=m)                {                    if((i+j)%2==0)                    {                        add((i-1)*m+j,n*m+(xx-1)*m+yy,g);                        add(n*m+(xx-1)*m+yy,(i-1)*m+j,0);                    }                    else                    {                        add((i-1)*m+j,n*m+(xx-1)*m+yy,sl);                        add(n*m+(xx-1)*m+yy,(i-1)*m+j,0);                    }                }            }        }    }}int Dfs(int u,int maxflow,int tt){    if(u==tt)return maxflow;    int ret=0;    for(int &i=cur[u];i!=-1;i=e[i].next)    {        int v=e[i].to;        int w=e[i].w;        if(w&&divv[v]==divv[u]+1)        {            int f=Dfs(v,min(maxflow-ret,w),tt);            e[i].w-=f;            e[i^1].w+=f;            ret+=f;            if(ret==maxflow)return ret;        }    }    return ret;}int makedivv(){    queue<int >s;    memset(divv,0,sizeof(divv));    divv[ss]=1;    s.push(ss);    while(!s.empty())    {        int u=s.front();        if(u==tt)return 1;        s.pop();        for(int i=head[u];i!=-1;i=e[i].next)        {            int v=e[i].to;            int w=e[i].w;            if(w&&divv[v]==0)            {                divv[v]=divv[u]+1;                s.push(v);            }        }    }    return 0;}int  Slove(){    getmap();    int ans=0;    while(makedivv()==1)    {        memcpy(cur,head,sizeof(head));        ans+=Dfs(ss,INF,tt);    }    return ans;}int main(){    int t;    int kase=0;    scanf("%d",&t);    while(t--)    {        int sum=0;        scanf("%d%d%d%d",&n,&m,&g,&sl);        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&a[i][j]);                sum+=a[i][j];            }        }        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&aa[i][j]);                sum+=aa[i][j];            }        }        int tmp=Slove();        printf("Case %d: %d\n",++kase,sum-tmp);    }}



0 0