您的位置:首页 > 其它

1515 - Pool construction

2015-08-17 13:16 295 查看






我有话说:

在这道题里,首先我们根据题目可以想到的是要预先算出把边界的洞填上草所需要的花费,同时在图中修改。然后就是要考虑内部的情况。所有的点都是草或者洞,栅栏是把草和洞隔开的作用,就对应上图论中“割”的概念。我们可以把所有的草连上同一个源点s,所有的洞连上同一个汇点t。从s到草的边我们记其容量为d的边,即对应只有把这条边切断,这个点才会属于“洞”这一集合,即和t相连。然后根据在图中的每一个点和他周围的点之间连上容量为b的边(栅栏),然后求这个图的最大流最小割即可。用的是Dinic算法。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>

using namespace std;
const int maxn=50*50+10;
const int INF=10000000000;
struct Edge{
int from,to,cap,flow;
};
bool operator < (const Edge& a,const Edge& b) {
return a.from<b.from||(a.from==b.from&&a.to<b.to);
}

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

void init(int 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(){
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
vis[s]=1;
d[s]=0;
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){
d[e.to]=d[x]+1;
vis[e.to]=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[x]+1==d[e.to]&&(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;
}
};
int w,h;
char pool[99][99];
inline int ID(int i,int j){
return i*w+j;
}
Dinic g;
int main()
{
int T,d,f,b;
cin>>T;
while(T--){
scanf("%d%d%d%d%d",&w,&h,&d,&f,&b);
for(int i=0;i<h;i++){
scanf("%s",pool[i]);
}
int cost=0;
for(int i=0;i<w;i++){
if(pool[0][i]=='.'){pool[0][i]='#';cost+=f;}
if(pool[h-1][i]=='.'){pool[h-1][i]='#';cost+=f;}
}
for(int i=0;i<h;i++){
if(pool[i][0]=='.'){pool[i][0]='#';cost+=f;}
if(pool[i][w-1]=='.'){pool[i][w-1]='#';cost+=f;}
}
g.init(w*h+2);
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
if(pool[i][j]=='#'){
int cap=INF;
if(i!=0&&i!=h-1&&j!=0&&j!=w-1)cap=d;
g.AddEdge(h*w,ID(i,j),cap);
}else{
g.AddEdge(ID(i,j),h*w+1,f);
}
if(i>0)g.AddEdge(ID(i,j),ID(i-1,j),b);
if(i<h-1)g.AddEdge(ID(i,j),ID(i+1,j),b);
if(j>0)g.AddEdge(ID(i,j),ID(i,j-1),b);
if(j<w-1)g.AddEdge(ID(i,j),ID(i,j+1),b);
}
}
printf("%d\n",cost+g.MaxFlow(h*w,h*w+1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: