[bzoj1066] [SCOI2007] 蜥蜴 - 网络流
在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃
到边界外。 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石
柱上。石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不
变),如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只蜥蜴在同一个
石柱上。
Input
输入第一行为三个整数r,c,d,即地图的规模与最大跳跃距离。以下r行为石竹的初始状态,0表示没有石柱
,1~3表示石柱的初始高度。以下r行为蜥蜴位置,“L”表示蜥蜴,“.”表示没有蜥蜴。
Output
输出仅一行,包含一个整数,即无法逃离的蜥蜴总数的最小值。
Sample Input
5 8 2 00000000 02000000 00321100 02000000 00000000 ........ ........ ..LLLL.. ........ ........
Sample Output
1
题解:徐趱鹏大佬一眼看出了裂点,的确,这种题目,自己有一个承受量的,一般需要裂点成一个终点,一个起点,然后流量为承受量,
然后就是S->入点无限流量,出点->终点无限流量去流。
这一道题目,建模型不难,关键在于代码实现建边,十分复杂,参考了hzw。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<queue> 6 #include<algorithm> 7 #define N 1007 8 #define inf 1000000007 9 using namespace std; 10 11 int r,c,d,S,T; 12 int cnt=1,head[N],next[N*N],rea[N*N],val[N*N]; 13 int ans,mp[21][21],mark[21][21]; 14 int dis[N]; 15 16 void add(int u,int v,int fee) 17 { 18 cnt++; 19 next[cnt]=head[u]; 20 head[u]=cnt; 21 rea[cnt]=v; 22 val[cnt]=fee; 23 } 24 bool judge(int x1,int y1,int x2,int y2) 25 { 26 if(((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))<=(d*d)&&mp[x1][y1]&&mp[x2][y2]) return 1; 27 return 0; 28 } 29 void build() 30 { 31 for(int x1=1;x1<=r;x1++) 32 for(int y1=1;y1<=c;y1++) 33 for(int x2=x1-d;x2<=x1+d;x2++) 34 for(int y2=y1-d;y2<=y1+d;y2++) 35 if(judge(x1,y1,x2,y2)&&(x1!=x2||y1!=y2)) add(mark[x1][y1]+r*c,mark[x2][y2],inf),add(mark[x2][y2],mark[x1][y1]+r*c,0); 36 for(int i=1;i<=r;i++) 37 for(int j=1;j<=c;j++) 38 if(mp[i][j]) add(mark[i][j],mark[i][j]+r*c,mp[i][j]),add(mark[i][j]+r*c,mark[i][j],0); 39 } 40 bool bfs() 41 { 42 memset(dis,-1,sizeof(dis)); 43 dis[S]=0; 44 queue<int>q; 45 q.push(S); 46 while (!q.empty()) 47 { 48 int u=q.front(); 49 q.pop(); 50 for (int i=head[u];i!=-1;i=next[i]) 51 { 52 int v=rea[i],cost=val[i]; 53 if (dis[v]==-1&&cost>0) 54 { 55 dis[v]=dis[u]+1; 56 if (v==T) return 1; 57 q.push(v); 58 } 59 } 60 } 61 return 0; 62 } 63 int dfs(int u,int MM) 64 { 65 int res=0; 66 if (u==T||MM==0) return MM; 67 for (int i=head[u];i!=-1;i=next[i]) 68 { 69 int v=rea[i],fee=val[i]; 70 if (dis[v]!=dis[u]+1) continue; 71 int x=dfs(v,min(MM,fee)); 72 if (x) 73 { 74 val[i]-=x,val[i^1]+=x; 75 MM-=x,res+=x; 76 if (MM==0) break; 77 } 78 } 79 return res; 80 } 81 int dinic() 82 { 83 int res=0; 84 while (bfs()) 85 { 86 int x=dfs(S,inf); 87 while (x) 88 { 89 res+=x; 90 x=dfs(S,inf); 91 } 92 } 93 return res; 94 } 95 int main() 96 { 97 memset(head,-1,sizeof(head)); 98 scanf("%d%d%d",&r,&c,&d); 99 int INK=r*c; 100 S=INK*2+1,T=INK*2+2; 101 char ch[21]; 102 for(int i=1;i<=r;i++) 103 { 104 scanf("%s",ch+1); 105 for(int j=1;j<=c;j++) 106 mp[i][j]=ch[j]-'0'; 107 } 108 int tot=0; 109 for(int i=1;i<=r;i++) 110 for(int j=1;j<=c;j++) 111 tot++,mark[i][j]=tot; 112 for(int i=1;i<=r;i++) 113 { 114 scanf("%s",ch+1); 115 for(int j=1;j<=c;j++) 116 if(ch[j]=='L') {add(S,mark[i][j],1),add(mark[i][j],S,0);ans++;} 117 } 118 for(int i=1;i<=d;i++) 119 for(int j=d+1;j<=r-d;j++) 120 { 121 add(mark[j][i]+INK,T,inf),add(T,mark[j][i]+INK,0); 122 add(mark[j][c-i+1]+INK,T,inf),add(T,mark[j][c-i+1]+INK,0); 123 } 124 for(int i=1;i<=d;i++) 125 for(int j=1;j<=c;j++) 126 { 127 add(mark[i][j]+INK,T,inf),add(T,mark[i][j]+INK,0); 128 add(mark[r-i+1][j]+INK,T,inf),add(T,mark[r-i+1][j]+INK,0); 129 } 130 build(); 131 int res=dinic(); 132 printf("%d",ans-res); 133 }