HDU 3820 Golden Eggs( 最小割 奇特建图)经典

Golden EggsTime Limit: 6000/3000 MS (Java/Others)Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 501Accepted Submission(s): 281

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 Specification1. 1 <= T <= 202. 1 <= N,M <= 503. 1 <= G,S <= 100004. 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

22 2 100 1001 15 11 41 11 4 85 95100 100 10 1010 10 100 100

Sample Output

Case 1: 9Case 2: 225

Author

hanshuai

Source

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

题意:有一个n*m的格子,可以放两种颜色我蛋:金蛋和银蛋。如果相邻格子里放同一颜色的蛋:如果为金蛋则减少价值为G,如果银蛋则减少价值为S。接下来n行m列表示放金蛋得到的价值mp1[][],再接下来n行m列表示放银蛋得到的价值mp2[][]。问最大能得到的价值。

解题:vs:源点,vt:汇点。建图:把n*m个格子分成奇偶两部分,,每个点都需要拆成两个点v,v’。奇点v:<vs , v , mp1[i][j]>,<v , v’ , INF>,<v’ , vt , mp2[i][j]>。与v相邻点u,<v , u’ , G>。偶点u:<vs , u , mp2[i][j]>,<u , u’ , INF>,<u’ , vt , mp1[i][j]>。与u相邻点v,<u , v’ , S>。这样图建好了,那么答案:mp1[][]+mp2[][] -maxflow。

/*最大流:SAP算法,与ISAP的差别就是不用预处理*/#include<stdio.h>#include<string.h>#include<queue>#include<algorithm>using namespace std;#define captype intconst 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]) //从这条可增流的路找到最多可增的流量Minif(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的距离(也可认为是高度)为相邻可流点的最小距离+1int 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+1gap[dis[u]]++;if(u!=sNode) u=edg[pre[u]^1].to; //退一条边}return ans;}int main(){int T,n,m,vs,vt,mp1[55][55],mp2[55][55],G,S;int dir[4][2]={0,1,0,-1,1,0,-1,0};scanf("%d",&T);for(int _case=1; _case<=T; ++_case){int ans=0;scanf("%d%d%d%d",&n,&m,&G,&S);for(int i=0; i<n; i++)for(int j=0; j<m; j++)scanf("%d",&mp1[i][j]) , ans+=mp1[i][j];for(int i=0; i<n; i++)for(int j=0; j<m; j++)scanf("%d",&mp2[i][j]) , ans+=mp2[i][j];vs = 2*n*m; vt = vs+1;init();for(int i=0; i<n; i++)for(int j=0; j<m; j++){int u=i*m+j;if((i+j)&1){addEdg(vs , u , mp1[i][j]);addEdg(u , u+n*m , INF);addEdg(u+n*m , vt , mp2[i][j]);for(int e=0; e<4; e++){int ti , tj;ti=i+dir[e][0];tj=j+dir[e][1];if(ti>=0&&ti<n&&tj>=0&&tj<m)addEdg(u , ti*m+tj+n*m , G);}}else{addEdg(vs , u , mp2[i][j]);addEdg(u , u+n*m , INF);addEdg(u+n*m , vt , mp1[i][j]);for(int e=0; e<4; e++){int ti , tj;ti=i+dir[e][0];tj=j+dir[e][1];if(ti>=0&&ti<n&&tj>=0&&tj<m)addEdg(u , ti*m+tj+n*m , S);}}}ans-=maxFlow_sap(vs , vt , vt+1);printf("Case %d: %d\n",_case , ans);}}

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

一直开到梦的尽头。你曾经说,

HDU 3820 Golden Eggs( 最小割 奇特建图)经典

相关文章:

你感兴趣的文章:

标签云: