您的位置:首页 > 编程语言 > Go语言

HDU 3820 Golden Eggs

2017-04-12 21:04 399 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3820

题意:
n*m的格子,每个格子放金蛋或银蛋,每个格子的金蛋和银蛋都有一个对应的点权,如果有两个金蛋相连,则需要G的代价,如果有两个银蛋相连,需要S的代价。

思路:

这道题和HDU的格子取数是一个套路。

在前面的格子取数问题中,我们奇偶建图,相邻点之间连INF就代表这两个点中至少会选择一个,由于是最小割,肯定是选择权值小的点。这道题目的建图稍微复杂点,因为每个格子有三种选择,即可以选择放金蛋或是放银蛋或空着。首先,我们还是要奇偶建图,把一方的金蛋与源点相连,银蛋与汇点相连,而另一方的金蛋与汇点相连,银蛋与源点相连。每一方的金蛋与自己的银蛋相连,容量为INF,说明要么放金蛋,要么放银蛋。而相邻的蛋颜色相同时则边的容量为代价。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

const int maxn = 1e5 + 5;
const int INF=0x3f3f3f3f;

struct Edge
{
int from,to,cap,flow;
Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){}
};

struct Dinic
{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[maxn];
bool vis[maxn];
int cur[maxn];
int d[maxn];

void init(int n)
{
this->n=n;
for(int i=0;i<n;++i) G[i].clear();
edges.clear();
}

void AddEdge(int from,int to,int cap)
{
edges.push_back( Edge(from,to,cap,0) );
edges.push_back( Edge(to,from,0,0) );
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

bool BFS()
{
queue<int> Q;
memset(vis,0,sizeof(vis));
vis[s]=true;
d[s]=0;
Q.push(s);
while(!Q.empty())
{
int x=Q.front(); Q.pop();
for(int i=0;i<G[x].size();++i)
{
Edge& e=edges[G[x][i]];
if(!vis[e.to] && e.cap>e.flow)
{
vis[e.to]=true;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}

int DFS(int x,int a)
{
if(x==t || a==0) return a;
int flow=0, f;
for(int &i=cur[x];i<G[x].size();++i)
{
Edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>0)
{
e.flow +=f;
edges[G[x][i]^1].flow -=f;
flow +=f;
a -=f;
if(a==0) break;
}
}
return flow;
}

int Maxflow(int s,int t)
{
this->s=s; this->t=t;
int flow=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow +=DFS(s,INF);
}
return flow;
}
}DC;

int n,m;
int G,S;
int map[105][55];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};

int main()
{
//freopen("D:\\input.txt","r",stdin);
int kase=0;
int T;
scanf("%d",&T);
while(T--)
{
int sum=0;
scanf("%d%d%d%d",&n,&m,&G,&S);
int src=0,dst=2*n*m+1;
DC.init(dst+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&map[i][j]);
sum+=map[i][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&map[i+n][j]);
sum+=map[i+n][j];
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int id1=(i-1)*m+j;
int id2=(i+n-1)*m+j;
int t=(i+j)%2;
//0为金色
if(t==0)
{
DC.AddEdge(src,id1,map[i][j]);    //金
DC.AddEdge(id2,dst,map[i+n][j]);  //银
DC.AddEdge(id1,id2,INF);
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x<1||x>n||y<1||y>m)  continue;
DC.AddEdge(id1,(x+n-1)*m+y,G);
}
}
else
{
DC.AddEdge(src,id1,map[i+n][j]);
DC.AddEdge(id2,dst,map[i][j]);
DC.AddEdge(id1,id2,INF);
for(int k=0;k<4;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x<1||x>n||y<1||y>m)  continue;
DC.AddEdge(id1,(x+n-1)*m+y,S);
}
}
}

int ans=sum-DC.Maxflow(src,dst);
printf("Case %d: %d\n",++kase,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: