题目
问题描述
有一个有N行M列的网格。在每个细胞里,你可以选择放入一个金蛋或银蛋,或者让它空着。如果你把一个鸡蛋放进细胞,你会得到一些点这取决于鸡蛋的颜色。但是对于每一对相邻的颜色相同的鸡蛋,如果是金色的就会失去G点,否则就会失去S点。当且仅当两个鸡蛋共享一条边时,两个鸡蛋是相邻的。试着把你的分数写得越高越好。
输入
第一行包含一个整数T,表示测试用例的数量。
在每个测试用例的第一行中有四个整数N, M, G和S。然后是2*N行,每一行包含M个整数。第i行Aij的第j个整数表示如果单元格(i,j)中有一个金蛋,您将得到的点。第j个整数(i+N)-第j行表示如果单元格(i,j)中有一个银蛋,你将得到的点。
Technical Specification
- 1 <= T <= 20
- 1 <= N,M <= 50
- 1 <= G,S <= 10000
- 1 <= Aij,Bij <= 10000
输出
对于每个测试用例,首先输出用例号,然后输出一行中的最高点。
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
#include <queue>
#include <cstring>
#include <cstdio>
#include <iostream>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=5000+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[N*7];
int head[N],d[N];
int tot,s,t;
void add(int from,int to,int len)
{
edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
while(!q.empty())
q.pop();
m(d,0);
q.push(s);
d[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(!d[y]&&l)
{
d[y]=d[x]+1;
q.push(y);
if(y==t)
return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x==t)
return flow;
int res=flow,k;
for(int i=head[x];i&&res;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(l&&d[y]==d[x]+1)
{
k=dinic(y,min(res,l));
if(!k)
{
d[y]=0;
continue;
}
edge[i].len-=k;
edge[i^1].len+=k;
res-=k;
}
}
return flow-res;
}
int main()
{
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
m(head,0);
tot=1;
int n,m,v1,v2,x;
ll sum=0;
scanf("%d%d%d%d",&n,&m,&v1,&v2);
s=0,t=n*m*2+1;
int k=n*m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int pos=(i-1)*m+j;
add(pos,pos+k,INF);
scanf("%d",&x);
sum+=x;
if((i+j)&1)
{
add(pos+k,t,x);
if(i>1)
add(pos,pos+k-m,v2);
if(i<n)
add(pos,pos+k+m,v2);
if(j>1)
add(pos,pos+k-1,v2);
if(j<m)
add(pos,pos+k+1,v2);
}
else
{
add(s,pos,x);
if(i>1)
add(pos,pos+k-m,v1);
if(i<n)
add(pos,pos+k+m,v1);
if(j>1)
add(pos,pos+k-1,v1);
if(j<m)
add(pos,pos+k+1,v1);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int pos=(i-1)*m+j;
scanf("%d",&x);
sum+=x;
if((i+j)&1)
add(s,pos,x);
else
add(pos+k,t,x);
}
}
ll maxflow=0;
while(bfs())
maxflow+=dinic(s,INF);
printf("Case %d: %lld\n",cas,sum-maxflow);
}
}