【BZOJ】1066: [SCOI2007]蜥蜴(最大流)
http://www.lydsy.com/JudgeOnline/problem.php?id=1066
本题想一想应该懂了的。
我们想啊,,每个点都有限制,每个点都可以跳到另一个有限制的点,每个有蜥蜴的点都可以跳到四周的有限制的点,,哈哈,自然会想到网络流。
其中很自然的可以相到,要表示每个点的容量限制,那么就拆点,一个上,一个下,容量为权值
然后向四周连接也就是某个点的下将距离范围内的某个点的上连接,容量为oo
源向蜥蜴连接,容量为1
可以跑到边界外的点的下向汇连接,容量为oo
跑一次最大流,答案就是蜥蜴总数减去最大流。
(表示第一次做还是错了,原因在源和汇的序号啊!!!!!现在直接限定源和汇的序号,以后一定要记住!)
#include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using namespace std; #define rep(i, n) for(int i=0; i<(n); ++i) #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);--i) #define for4(i,a,n) for(int i=(a);i>(n);--i) #define CC(i,a) memset(i,a,sizeof(i)) #define read(a) a=getint() #define print(a) printf("%d", a) #define dbg(x) cout << #x << " = " << x << endl #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; } inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; } inline const int max(const int &a, const int &b) { return a>b?a:b; } inline const int min(const int &a, const int &b) { return a<b?a:b; } const int N=1000, M=N*4000, oo=~0u>>1; int ihead[N], cnt=1, cur[N], gap[N], d[N], p[N], n, m, g, a[22][22]; struct ED { int from, to, cap, next; } e[M]; inline const int id(const int &x, const int &y) { return (x-1)*m+y; } inline const bool check(const int &i, const int &j, const int &x, const int &y) { return ((i-x)*(i-x)+(j-y)*(j-y))<=g*g; } inline void add(const int &u, const int &v, const int &w) { e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v; e[cnt].from=u; e[cnt].cap=w; e[++cnt].next=ihead[v]; ihead[v]=cnt; e[cnt].to=u; e[cnt].from=v; e[cnt].cap=0; } int isap(const int &s, const int &t, const int &n) { for1(i, 0, n) cur[i]=ihead[i]; int ret=0, i, f, u=s; gap[0]=n; while(d[s]<n) { for(i=cur[u]; i; i=e[i].next) if(e[i].cap && d[u]==d[e[i].to]+1) break; if(i) { p[e[i].to]=cur[u]=i; u=e[i].to; if(u==t) { for(f=oo; u!=s; u=e[p[u]].from) f=min(f, e[p[u]].cap); for(u=t; u!=s; u=e[p[u]].from) e[p[u]].cap-=f, e[p[u]^1].cap+=f; ret+=f; } } else { if(! (--gap[d[u]]) ) break; d[u]=n; cur[u]=ihead[u]; for(i=ihead[u]; i; i=e[i].next) if(e[i].cap && d[u]>d[e[i].to]+1) d[u]=d[e[i].to]+1; ++gap[d[u]]; if(u!=s) u=e[p[u]].from; } } return ret; } int main() { read(n); read(m); read(g); int s=900, t=901, now, tp, ans=0; char c; for1(i, 1, n) for1(j, 1, m) { for(c=getchar(); c<'0'||c>'9'; c=getchar()); tp=c-'0'; if(tp) { now=id(i, j); a[i][j]=tp; add(now, now+410, tp); } } for1(i, 1, n) for1(j, 1, m) { for(c=getchar(); c!='L'&&c!='.'; c=getchar()); if(c=='L') add(s, id(i, j), 1), ++ans; } for1(i, 1, n) for1(j, 1, m) if(a[i][j]) for(int x=i-g; x<=i+g; ++x) for(int y=j-g; y<=j+g; ++y) if(a[x][y] && !(i==x && j==y) && check(i, j, x, y)) add(id(i, j)+410, id(x, y), oo); for1(i, 1, g) for1(j, 1, m) add(id(i, j)+410, t, oo), add(id(n-i+1, j)+410, t, oo); for1(i, 1, g) for1(j, 1, n) add(id(j, i)+410, t, oo), add(id(j, m-i+1)+410, t, oo); print(ans-isap(s, t, t+1)); return 0; }
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<=3
博客地址:www.cnblogs.com/iwtwiioi 本文为博主原创文章,未经博主允许不得转载。一经发现,必将追究法律责任。