BZOJ 1066 【SCOI2007】 蜥蜴
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; }