Time Limit: 1 Sec
Memory Limit: 162 MB
Description
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不
变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
Input
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
Output
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
HINT
100%的数据满足:1<=r, c<=20, 1<=d<=4
题目分析
首先可以把问题转化为蜥蜴总数-最大逃离数,然后开始建图
每个石柱拆成入点和出点
并从入点向出点连边,容量为自己的高度
对于每个可以直接跳出边界的石柱
从其出点向超级汇点连边,容量为inf
对于每个有蜥蜴的石柱
由超级源点向其入点连边,容量为1
对于原图中互相可达的石柱
从一个石柱的出点向另一个石柱的入点连边,容量为inf
跑最大流即可
#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
int read()
{
int f=1,x=0;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return f*x;
}
const int inf=1e8;
const int maxn=10010;
int n,m,d,s=0,t,sum;
struct node{int v,f,nxt;}E[maxn*10];
int head[maxn],tot=1;
int judge[maxn],lev[maxn],ans;
char ss[25];
void add(int u,int v,int f)
{
E[++tot].nxt=head[u];
E[tot].v=v; E[tot].f=f;
head[u]=tot;
}
int dis(int x1,int y1,int x2,int y2)
{
int x=x1-x2; x*=x;
int y=y1-y2; y*=y;
return x+y;
}
bool bfs()
{
queue<int> q; q.push(s);
memset(lev,-1,sizeof(lev)); lev[s]=0;
while(!q.empty())
{
int u=q.front(); q.pop();
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(lev[v]==-1&&E[i].f)
{
lev[v]=lev[u]+1;
if(v==t)return true;
q.push(v);
}
}
}
return false;
}
int dfs(int u,int cap)
{
if(u==t) return cap;
int flow=cap;
for(int i=head[u];i;i=E[i].nxt)
{
int v=E[i].v;
if( lev[v]==lev[u]+1&&flow&&E[i].f>0)
{
int f=dfs(v,min(flow,E[i].f));
E[i].f-=f; E[i^1].f+=f;
flow-=f;
}
}
return cap-flow;
}
int main()
{
n=read();m=read();d=read();
t=n*m<<1|1;
for(int i=1;i<=n;++i)
{
scanf("%s",&ss);
for(int j=0;j<m;++j)
{
int num1=(i-1)*m+j+1,num2=num1+n*m,k=ss[j]-'0';
if(k==0){ judge[num1]=1; continue;}//记录这个点没有石柱
add(num1,num2,k); add(num2,num1,0);//每个点由自己的入点向自己的出点连边
if(i-d<1||i+d>n||j-d+1<1||j+d+1>m) add(num2,t,inf),add(t,num2,0);//可以直接跳出去的点,从出点到超汇连边
}
}
for(int i=1;i<=n;++i)
{
scanf("%s",&ss);
for(int j=0;j<m;++j)
{
int num=(i-1)*m+j+1;
if(ss[j]=='L'){
sum++;
add(s,num,1); add(num,s,0);//有蜥蜴的石柱,超源向其入点连边
}
}
}
for(int x1=1;x1<=n;++x1)
for(int y1=1;y1<=m;++y1)
for(int x2=1;x2<=n;++x2)
for(int y2=1;y2<=m;++y2)
if(dis(x1,y1,x2,y2)<=d*d)
{
int num1=(x1-1)*m+y1+n*m,num2=(x2-1)*m+y2;
if(judge[num2]) continue;
add(num1,num2,inf); add(num2,num1,0);
//互相可达的石柱,从其中一个的出点向另一个的入点连边
}
while(bfs())
ans+=dfs(s,inf);
printf("%d",sum-ans);
return 0;
}