http://acm.hdu.edu.cn/showproblem.php?pid=4859
题意:
欢迎来到珠海!
由于土地资源越来越紧张,使得许多海滨城市都只能依靠填海来扩展市区以求发展。作为Z市的决策人,在仔细观察了Z市地图之后,你准备通过填充某些海域来扩展Z市的海岸线到最长,来吸引更多的游客前来旅游度假。为了简化问题,假设地图为一个N*M的格子,其中一些是陆地,一些是可以填充的浅海域,一些是不可填充的深海域。这里定义海岸线的长度为一个联通块陆地(可能包含浅海域填充变为的陆地)的边缘长度,两个格子至少有一个公共边,则视为联通。
值得注意的是,这里Z市的陆地区域可以是不联通的,并且整个地图都处在海洋之中,也就是说,Z市是由一些孤岛组成的,比如像,夏威夷?
你的任务是,填充某些浅海域,使得所有岛屿的海岸线之和最长。
思路:
这道题目的话和最大独立点权是比较相似的。
首先考虑一个格子的情况,它的海岸线长度之和就是它周围有多少海域,如果它四条边都是海域,那么它的海岸线长度之和就是4,如果周围有陆地则会相应的减少。
那么其实这道题目就是要我们求最大相邻的'D'和'.' 的总对数!!
先在格子周围加上一圈'D',先将这个图分成一个二分图,左边为X集,右边为Y集(X与源点相连,表示陆地,Y与汇点相连,表示海域),接下来分析每个格子:
1、若相邻则连边,容量1。
2、若当前点在地图上是 . 但是却被分到了Y集,或者当前点是 D ,却被分到了X集,就和源点连一条INF的边。
3、若当前点在地图上是 . 并且被分到了X集,或者当前点是 D ,被分到了Y集,就和汇点连一条INF的边。
所以只有 . --> . 或者 D --> D ,也就是类型相同的,才能从源流向汇。此时需要减少1的海岸线,因为不是'.'与'D'相邻。最小割求出最小的相同格子相邻的对数。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn=1e6+; int n, m;
int mp[][]; int dx[]={,,,-};
int dy[]={,-,,}; 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=;i<n;++i) G[i].clear();
edges.clear();
} void AddEdge(int from,int to,int cap)
{
edges.push_back( Edge(from,to,cap,) );
edges.push_back( Edge(to,from,,) );
m=edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
queue<int> Q;
memset(vis,,sizeof(vis));
vis[s]=true;
d[s]=;
Q.push(s);
while(!Q.empty())
{
int x=Q.front(); Q.pop();
for(int i=;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]+;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x,int a)
{
if(x==t || a==) return a;
int flow=, f;
for(int &i=cur[x];i<G[x].size();++i)
{
Edge &e=edges[G[x][i]];
if(d[e.to]==d[x]+ && (f=DFS(e.to,min(a,e.cap-e.flow) ) )>)
{
e.flow +=f;
edges[G[x][i]^].flow -=f;
flow +=f;
a -=f;
if(a==) break;
}
}
return flow;
} int Maxflow(int s,int t)
{
this->s=s; this->t=t;
int flow=;
while(BFS())
{
memset(cur,,sizeof(cur));
flow +=DFS(s,INF);
}
return flow;
}
}DC; int main()
{
//freopen("in.txt", "r", stdin);
char s[];
int kase=;
int T;
scanf("%d",&T);
while(T--)
{
memset(mp,,sizeof(mp));
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",s);
for(int j=;j<m;j++)
{
if(s[j]=='E') mp[i][j+]=;
else if(s[j]=='.') mp[i][j+]=;
}
}
int src=,dst=(n+)*(m+)+;
DC.init(dst+);
for(int i=;i<=n+;i++)
{
for(int j=;j<=m+;j++)
{
if((i+j)%==)
{
if(mp[i][j]==) DC.AddEdge(i*(m+)+j+,dst,INF);
else if(mp[i][j]==) DC.AddEdge(src,i*(m+)+j+,INF);
}
else
{
if(mp[i][j]==) DC.AddEdge(i*(m+)+j+,dst,INF);
else if(mp[i][j]==) DC.AddEdge(src,i*(m+)+j+,INF);
}
for(int k=;k<;k++)
{
int x=i+dx[k];
int y=j+dy[k];
if(x< || x>n+ || y< || y>m+) continue;
DC.AddEdge(i*(m+)+j+,x*(m+)+y+,);
}
}
}
int ans=DC.Maxflow(src,dst);
printf("Case %d: %d\n",++kase,(n+)*(m+)+(n+)*(m+)-ans);
}
return ;
}