[SCOI2007] 蜥蜴
题目描述
在一个 行 列的网格地图中有一些高度不同的石柱,第 行 列的石柱高度为 。
一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。
每行每列中相邻石柱的距离为 ,蜥蜴的跳跃距离是 ,即蜥蜴可以跳到平面距离不超过 的任何一个石柱上。
石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减 (如果仍然落在地图内部,则到达的石柱高度不变)。
如果该石柱原来高度为 ,则蜥蜴离开后消失,以后其他蜥蜴不能落脚。
任何时刻不能有两只蜥蜴在同一个石柱上。
对于 的数据满足:,,。
题目分析
最近在做网络流的题,也是因为考试遇到了,所以学了一下网络流。但是很菜,也就只会板子了。
学了之后发现,只要知道拆点这个方法,这道题就很好想了。
因为 限制条件:通过次数 是在点上,所以把每个值不为零的点分配两个编号,一个入点,一个出点。柱子高度为零的点忽略不管。
-
入点到出点连边,容量为这个点柱子高度,即可通过的蜥蜴数。
-
然后每两个可以到达的点的出点都与对方的入点连边,容量正无穷。
-
每个可以到达地图外的点与汇点连边,容量正无穷。
-
原点到每个有蜥蜴的点连边,容量为 1 。
这样图的模型就建好了,只需要再跑一个最大流就解决了。得到的最大流就是可以逃离的蜥蜴数,用总量减一下就是答案了。
Code
点击查看代码
#include<bits/stdc++.h> using namespace std; const int N=4005,M=4e5,INF=0x3f3f3f3f; int nxt[M],h[N],ver[M],w[M],co=1; int de[N],no[N*2]; int n,m,d,s,t; int mp[25][25],id[25][25],c=1; inline int read(){ int sum=0,f=1;char a=getchar(); while(a<'0' || a>'9'){if(a=='-') f=-1;a=getchar();} while(a>='0' && a<='9') sum=sum*10+a-'0',a=getchar(); return sum*f; } void add(int x,int y,int z){ nxt[++co]=h[x],h[x]=co,ver[co]=y,w[co]=z; nxt[++co]=h[y],h[y]=co,ver[co]=x,w[co]=0; } bool ch(int x,int y,int x1,int y1){ int t1=abs(x-x1),t2=abs(y-y1); double tmp=sqrt(1.0*t1*t1+1.0*t2*t2); if(tmp<=d) return 1; return 0; } bool bfs(){ memset(de,0,sizeof de); queue<int> q; q.push(s); de[s]=1,no[s]=h[s]; while(q.size()){ int x=q.front(); q.pop(); for(int i=h[x];i;i=nxt[i]){ int y=ver[i]; if(w[i] && !de[y]){ q.push(y); no[y]=h[y]; de[y]=de[x]+1; if(y==t) return 1; } } } return 0; } int dfs(int x,int flow){ if(x==t) return flow; int rest=flow,k,i; for(i=h[x];i && rest;i=nxt[i]){ int y=ver[i]; if(de[y]==de[x]+1 && w[i]){ k=dfs(y,min(rest,w[i])); if(!k) de[y]=0; w[i]-=k; w[i^1]+=k; rest-=k; } } no[x]=i; return flow-rest; } int main(){ char a;int tot=0; n=read(),m=read(),d=read(); memset(mp,0x3f,sizeof mp); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) cin>>a,mp[i][j]=a-'0'; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(mp[i][j]){ id[i][j]=++c;++c; add(id[i][j],c,mp[i][j]); } s=++c,t=++c; memset(de,0,sizeof de); for(int x=0;x<=n;++x) for(int y=0;y<=m;++y) for(int x1=1;x1<=n+1;++x1) for(int y1=1;y1<=m+1;++y1) if((x!=x1 || y!=y1) && mp[x][y] && mp[x1][y1] && ch(x,y,x1,y1)){ if((!x || !y) && (x1==n+1 || y==m+1)) continue; if(!x || !y){ if(!de[id[x1][y1]]){de[id[x1][y1]]=1;add(id[x1][y1]^1,t,INF);} } else if(x1==n+1 || y1==m+1){ if(!de[id[x][y]]){de[id[x][y]]=1;add(id[x][y]^1,t,INF);} } else add(id[x][y]^1,id[x1][y1],INF); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ cin>>a; if(a=='L') add(s,id[i][j],1),++tot; } int ans=0,flow=0; while(bfs()){ while(flow=dfs(s,INF)) ans+=flow; } cout<<tot-ans; return 0; }
结语
这道题思路其实不难,但是建图的代码实现有些细节要自己慢慢调。
多交几次,或者去 BZOJ 白嫖数据也可以
本文作者:_yolanda
本文链接:https://www.cnblogs.com/yolanda-yxr/p/16463996.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步