bzoj1066 蜥蜴
Description
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
Input
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
Output
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
Sample Input
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
Sample Output
HINT
100%的数据满足:1<=r, c<=20, 1<=d<=4
虽然它需要每个蜥蜴不能同时在同一石柱上,但是实际上我们可以让蜥蜴按一定顺序一个一个走,不同时走。那这些排列顺序里一定有一种方案是最优的。
为什么呢?因为最优解不可能出现蜥蜴A跳出去的路径中经过蜥蜴B的初始位置(标记为A->B),并且蜥蜴B跳出去的路径中经过蜥蜴A的初始位置(标记为B->A)。
也就是说要么蜥蜴A跳出去的路径中经过蜥蜴B的初始位置,那么蜥蜴B应该排在蜥蜴A前面走;要么蜥蜴B跳出去的路径中要经过蜥蜴A的初始位置,那么蜥蜴A应该排在蜥蜴B前走。
同样更不会出现A->B且B->C且C->A的情况、A->B且B->C且C->D且D->A的情况,等等。也就是说这个一定是有拓扑序的,不会有环。
那么我们在跑网络流的时候可以不用管它的顺序,直接跑最大流,只要是可行流就一定是可行解,因为一定会有一个蜥蜴的排列顺序满足这个可行流。每个石柱拆成两个点,这两个点间连一条最大流量为石柱高度的点,从S向每个蜥蜴所在石柱连一条最大流量为1的边。T与每个能跳出地图的石柱连一条最大流量为INF的边。石柱与石柱间若距离<=d也相互连最大流量为INF的边。
所以就拆点Dinic。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; const int maxn=400*2+10,maxm=maxn*maxn,INF=0x3f3f3f3f; int n,r,c,d,tot_col,tot_m,sz,S,T; int bh[maxn][maxn]; char kk; struct Col{ int x,y,h; }col[maxn]; int aa,ff;char cc; int read() { aa=0;ff=1;cc=getchar(); while(cc<'0'||cc>'9') { if(cc=='-') ff=-1; cc=getchar(); } while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); return aa*ff; } struct Node{ int x,y,flow,cap; Node(){} Node(int x,int y,int cap):x(x),y(y),cap(cap){flow=0;} }node[2*maxm]; int cur[maxn],fir[maxn],nxt[2*maxm],e=1; void add(int x,int y,int z) { node[++e]=Node(x,y,z); nxt[e]=fir[x];fir[x]=e; node[++e]=Node(y,x,0); nxt[e]=fir[y];fir[y]=e; } int dis[maxn],zz[maxn]; bool BFS() { int s=1,t=0,x,y,z; memset(dis,-1,sizeof(dis)); dis[S]=0;zz[++t]=S; while(s<=t) { x=zz[s]; for(y=fir[x];y;y=nxt[y]) { z=node[y].y; if(dis[z]!=-1||node[y].flow>=node[y].cap) continue; dis[z]=dis[x]+1; zz[++t]=z; } s++; } return dis[T]!=-1; } int DFS(int pos,int maxf) { if(pos==T||!maxf) return maxf; int now,z,rs=0; for(int &y=cur[pos];y;y=nxt[y]) { z=node[y].y; if(dis[z]!=dis[pos]+1||node[y].flow>=node[y].cap) continue; now=DFS(z,min(maxf,node[y].cap-node[y].flow)); node[y].flow+=now; node[y^1].flow-=now; maxf-=now; rs+=now; } if(!rs) dis[pos]=-1; return rs; } int Dinic() { int rs=0; while(BFS()) { memcpy(cur,fir,sizeof(fir)); rs+=DFS(S,INF); } return rs; } bool ok(int x,int y) { return sqrt((double)(col[x].x-col[y].x)*(col[x].x-col[y].x)+(double)(col[x].y-col[y].y)*(col[x].y-col[y].y))<=(double)d; } int main() { r=read();c=read();d=read(); int x; for(int i=1;i<=r;++i) { kk=getchar(); while(kk<'0'||kk>'9') kk=getchar(); x=kk-'0'; for(int j=1;j<=c;++j) { if(x) { col[++tot_col].x=i; col[tot_col].y=j; col[tot_col].h=x; bh[i][j]=tot_col; } kk=getchar();x=kk-'0'; } } S=2*tot_col+1;T=S+1; for(int i=1;i<=tot_col;++i) { add(i,i+tot_col,col[i].h); if(min(col[i].x,r-col[i].x+1)<=d||min(col[i].y,c-col[i].y+1)<=d) add(i+tot_col,T,INF); for(int j=1;j<=tot_col;++j){ if(i==j) continue; else if(ok(i,j)) add(i+tot_col,j,INF); } } for(int i=1;i<=r;++i) { kk=getchar(); while(kk!='.'&&kk!='L') kk=getchar(); for(int j=1;j<=c;++j) { if(kk=='L') add(S,bh[i][j],1),n++; kk=getchar(); } } printf("%d",n-Dinic()); return 0; }