bzoj1066: [SCOI2007]蜥蜴
http://www.lydsy.com/JudgeOnline/problem.php?id=1066
每个柱子拆成两个点 i<<1,i<<1|1,之间连流量为高度的边
如果第i根柱子有蜥蜴,S向i<<1连边,流量为1
如果第i根柱子能跳出去,i<<1|1向T连边,流量为inf
如果第i根柱子能跳到第j根柱子,i<<1|1向j<<1连边,流量为inf
至于每根柱子每个时刻只能有一个蜥蜴,不需要管,总可以通过先后顺序调整成满足条件
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define N 900 #define M 21500 const int inf=1e9; char s[21]; int mp[21][21]; int cnt; int id[21][21]; int tot=1; int front[N],nxt[M<<1],to[M<<1],val[M<<1],from[M<<1]; int lev[N],num[N]; int path[N]; int cur[N]; int src,decc; void add(int u,int v,int w) { to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w; to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=0; //cout<<u<<' '<<v<<' '<<w<<'\n'; } bool bfs() { queue<int>q; for(int i=src;i<=decc;++i) lev[i]=decc; q.push(decc); lev[decc]=0; int now,t; while(!q.empty()) { now=q.front(); q.pop(); for(int i=front[now];i;i=nxt[i]) { t=to[i]; if(lev[t]==decc && val[i^1]) { lev[t]=lev[now]+1; q.push(t); } } } return lev[src]!=decc; } int augment() { int now=decc,flow=inf; int i; while(now!=src) { i=path[now]; flow=min(flow,val[i]); now=from[i]; } now=decc; while(now!=src) { i=path[now]; val[i]-=flow; val[i^1]+=flow; now=from[i]; } return flow; } int isap() { int flow=0; if(!bfs()) return 0; memset(num,0,sizeof(num)); for(int i=src;i<=decc;++i) num[lev[i]]++,cur[i]=front[i]; int now=src,t; while(lev[src]<decc) { if(now==decc) { flow+=augment(); now=src; } bool advanced=false; for(int i=cur[now];i;i=nxt[i]) { t=to[i]; if(lev[t]==lev[now]-1 && val[i]) { advanced=true; path[t]=i; cur[now]=i; now=t; break; } } if(!advanced) { int mi=decc; for(int i=front[now];i;i=nxt[i]) if(val[i]) mi=min(mi,lev[to[i]]); if(!--num[lev[now]]) break; num[lev[now]=mi+1]++; cur[now]=front[now]; if(now!=src) now=from[path[now]]; } } return flow; } int main() { int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;++i) { scanf("%s",s+1); for(int j=1;j<=m;++j) { mp[i][j]=s[j]-'0'; if(mp[i][j]) id[i][j]=++cnt; } } src=1; decc=(cnt<<1|1)+1; int x,y; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { if(!mp[i][j]) continue; add(id[i][j]<<1,id[i][j]<<1|1,mp[i][j]); for(int r=1;r<=n;++r) for(int c=1;c<=m;++c) { if(!mp[r][c] || (r==i && c==j)) continue; if((r-i)*(r-i)+(c-j)*(c-j)<=k*k) add(id[i][j]<<1|1,id[r][c]<<1,mp[i][j]); //if(abs(r-i)+abs(c-j)<=k) add(id[i][j]<<1|1,id[r][c]<<1,inf); } if(i<=k || j<=k || n-i<k || m-j<k) add(id[i][j]<<1|1,decc,inf); } int sum=0; for(int i=1;i<=n;++i) { scanf("%s",s+1); for(int j=1;j<=m;++j) { if(s[j]=='L') { sum++; add(src,id[i][j]<<1,1); } } } cout<<sum-isap(); }
1066: [SCOI2007]蜥蜴
Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4407 Solved: 2245
[Submit][Status][Discuss]
Description
在一个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..
........
........
00000000
02000000
00321100
02000000
00000000
........
........
..LLLL..
........
........
Sample Output
1
HINT
100%的数据满足:1<=r, c<=20, 1<=d<=4