在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个石柱上。
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
5 8 2
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
1
本题为2007年四川省选题,用来练习网络流……
直接每根互相能到达的柱子上连一条边权为高度的边肯定是不可做的,这题的构图方法有点意思:我们把图上的每个点拆成一个入点和一个出点,然后自己的入点和出点之间连一条容量为高度的边,相互能到达的柱子建一条由一根柱子的出点连向另一根竹子的入点的容量为∞的边,然后源点向所有有蜥蜴的柱子的入点连一条容量为1的边,所有能出边界的柱子向汇点连一条容量为1的边。然后跑一遍dinic就好了。
然而本人由于SB第一次交的时候RE……
边有点多,当图最大的时候,边数有40000+条,然而本人第一次交的时候边数开的10000……废话不多说,下面附代码。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<climits> 5 struct edge{ 6 int d,next,data; 7 }e[50010]; 8 int f[410],efree=1,i,j,r,c,d,dis[410],p,ans,k,l,cnt,h,t,q[100010]; 9 char ch[50][50],cha; 10 inline int min(int x,int y){ 11 if(x<y)return x; 12 return y; 13 } 14 inline void add(int x,int y,int z){ 15 e[++efree].d=y; 16 e[efree].next=f[x]; 17 e[efree].data=z; 18 f[x]=efree; 19 } 20 inline bool bfs(){ 21 memset(dis,-1,sizeof(dis)); 22 dis[0]=1; 23 h=0;t=1; 24 q[t]=0; 25 while(h!=t){ 26 p=q[++h]; 27 for(int i=f[p];i;i=e[i].next) 28 if(dis[e[i].d]==-1&&e[i].data>0){ 29 dis[e[i].d]=dis[p]+1; 30 q[++t]=e[i].d; 31 } 32 } 33 return dis[2*r*c+1]>0; 34 } 35 inline int dfs(int x,int y){ 36 if(x==2*r*c+1)return y; 37 if(y==0)return 0; 38 int tmp=0,re; 39 for(int i=f[x];i;i=e[i].next) 40 if(dis[e[i].d]==dis[x]+1&&e[i].data>0){ 41 re=dfs(e[i].d,min(e[i].data,y-tmp)); 42 tmp+=re; 43 e[i].data-=re; 44 e[i^1].data+=re; 45 if(y==tmp)return y; 46 } 47 return tmp; 48 } 49 int main(){ 50 scanf("%d%d%d\n",&r,&c,&d); 51 for(i=1;i<=r;i++){ 52 for(j=1;j<=c;j++){ 53 ch[i][j]=getchar(); 54 if(ch[i][j]!='0'){ 55 add((i-1)*c+j,(i-1)*c+j+r*c,ch[i][j]-'0'); 56 add((i-1)*c+j+r*c,(i-1)*c+j,0); 57 }//每根柱子的入点连向出点 58 } 59 cha=getchar(); 60 } 61 for(i=1;i<=r;i++) 62 for(j=1;j<=c;j++) 63 if(ch[i][j]!='0') 64 for(k=i-d;k<=i+d;k++) 65 for(l=j-d;l<=j+d;l++) 66 if(sqrt((i-k)*(i-k)+(j-l)*(j-l))<=d&&(i!=k||j!=l)&&ch[k][l]!='0'&&(i>d||r-i>=d||j>d||c-j>=d)){ 67 add((i-1)*c+j+r*c,(k-1)*c+l,INT_MAX); 68 add((k-1)*c+l,(i-1)*c+j+r*c,0); 69 }//相互可以到达的柱子连边 70 for(i=1;i<=r;i++) 71 for(j=1;j<=c;j++) 72 if(ch[i][j]!='0'&&(i<=d||r-i<d||j<=d||c-j<d)){ 73 add((i-1)*c+j+r*c,2*r*c+1,INT_MAX); 74 add(2*r*c+1,(i-1)*c+j+r*c,0); 75 }//能够出边界的柱子连向汇点 76 for(i=1;i<=r;i++){ 77 for(j=1;j<=c;j++){ 78 ch[i][j]=getchar(); 79 if(ch[i][j]=='L'){ 80 cnt++; 81 add(0,(i-1)*c+j,1); 82 add((i-1)*c+j,0,0); 83 }//源点连向有蜥蜴的柱子 84 } 85 cha=getchar(); 86 } 87 while(bfs())ans+=dfs(0,INT_MAX); 88 printf("%d",cnt-ans); 89 return 0; 90 }