BZOJ 1066 【SCOI2007】 蜥蜴

时间:2023-11-24 12:40:50

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

  过了这么久,终于对简单的网络流的题有感觉了……虽然这道题的确很水

  这道题其实就是要求最多可以有多少条蜥蜴逃出去,再用蜥蜴总数减一下就可以了。于是把每根石柱拆成两个点,流量为石柱的高度;然后两个点之间暴力连边,跑一遍Dinic即可。边数较大,请自觉开大空间。

  这道题Discuss里有人在说距离是曼哈顿距离……不过$d<=4$好像和欧式距离也没有什么区别吧……汗……

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout);
#define maxn 1010
#define maxm 1000010
#define INF (1<<25) using namespace std;
typedef long long llg; int n,m,d,S,T,dep[maxn],de[maxn],ans;
int head[maxn],next[maxm],to[maxm],c[maxm],tt=1; int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') q=1,c=getchar();
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
} int ji(int x){return x*x;}
void link(int x,int y,int z){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
c[tt-1]=z;
} bool bfs(){
for(int i=1;i<=T;i++) dep[i]=-1;
int l=0,r=0; de[r++]=S; dep[S]=1;
while(l!=r){
int u=de[l++];
for(int i=head[u],v;v=to[i],i;i=next[i])
if(c[i] && dep[v]==-1)
dep[v]=dep[u]+1,de[r++]=v;
}
return dep[T]!=-1;
} int dfs(int u,int low){
int res=0,now=0;
if(u==T || !low) return low;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(c[i] && dep[v]==dep[u]+1){
res=dfs(v,min(low-now,c[i]));
c[i]-=res; c[i^1]+=res; now+=res;
}
if(!now) dep[u]=-INF;
return now;
} int main(){
n=getint(); m=getint(); d=getint();
S=n*m*2+1; T=S+1;
for(int i=1,now=1;i<=n;i++)
for(int j=1;j<=m;j++,now++){
char c=getchar();
while(c>'9'||c<'0') c=getchar();
if(c!='0'){
link(now,now+n*m,c-'0');
if(min(i,n-i+1)<=d) link(now+n*m,T,INF);
if(min(j,m-j+1)<=d) link(now+n*m,T,INF);
for(int x=1,nn=1;x<=n;x++)
for(int y=1;y<=m;y++,nn++)
if(ji(i-x)+ji(j-y)<=d*d)
if(i!=x || j!=y)
link(now+n*m,nn,INF);
}
}
for(int i=1,now=1;i<=n;i++)
for(int j=1;j<=m;j++,now++){
char c=getchar();
while(c!='.' && c!='L') c=getchar();
if(c=='.') continue;
link(S,now,1); ans++;
}
while(bfs()) ans-=dfs(S,INF);
printf("%d",ans);
return 0;
}