——深深感谢你——|

_yolanda

园龄:3年7个月粉丝:11关注:15

2022-07-10 20:44阅读: 42评论: 0推荐: 0

[SCOI2007] 蜥蜴

题目描述

在一个 rc 列的网格地图中有一些高度不同的石柱,第 ij 列的石柱高度为 hi,j

一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外。

每行每列中相邻石柱的距离为 1,蜥蜴的跳跃距离是 d,即蜥蜴可以跳到平面距离不超过 d 的任何一个石柱上。

石柱都不稳定,每次当蜥蜴跳跃时,所离开的石柱高度减 1(如果仍然落在地图内部,则到达的石柱高度不变)。

如果该石柱原来高度为 1,则蜥蜴离开后消失,以后其他蜥蜴不能落脚。

任何时刻不能有两只蜥蜴在同一个石柱上。

对于 100% 的数据满足:1r,c201d41h3

题目分析

最近在做网络流的题,也是因为考试遇到了,所以学了一下网络流。但是很菜,也就只会板子了。

学了之后发现,只要知道拆点这个方法,这道题就很好想了。

因为 限制条件:通过次数 是在点上,所以把每个值不为零的点分配两个编号,一个入点,一个出点。柱子高度为零的点忽略不管。

  1. 入点到出点连边,容量为这个点柱子高度,即可通过的蜥蜴数。

  2. 然后每两个可以到达的点的出点都与对方的入点连边,容量正无穷。

  3. 每个可以到达地图外的点与汇点连边,容量正无穷。

  4. 原点到每个有蜥蜴的点连边,容量为 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 中国大陆许可协议进行许可。

posted @   _yolanda  阅读(42)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 化身孤岛的鲸 周深
  2. 2 像鸟儿一样(Live) 周深
  3. 3 Rubia 周深
  4. 4 痕迹 周深
像鸟儿一样(Live) - 周深
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

像鸟儿一样 (Live) - 周深

词:陈曦

曲:陈曦

像鸟儿一样

像鸟儿一样

飞过月光海港

飞过月光海港

看过山色极光

看过山色极光

听过雨露悲伤

听过雨露悲伤

像鸟儿一样

像鸟儿一样

路过银河星光

路过银河星光

错过烟花绽放

错过烟花绽放

尝过失措惊慌

像鸟儿一样

像鸟儿一样

记得家的方向

记得家的方向

认得人的模样

认得人的模样

却忘了飞不过时光

像鸟儿一样

像鸟儿一样

活得匆匆忙忙

活得匆匆忙忙

爱得两两相望

爱得两两相望

却不知终将天各一方

多想像鸟儿一样扇动翅膀

多想像鸟儿一样扇动翅膀

展开对天空的想象

心怀梦想

心怀梦想

借着太阳的光芒 风的力量

多想像鸟儿一样目视前方

多想像鸟儿一样目视前方

拥抱这命运的无常

满怀期望

凭着自己的臂膀

像鸟儿一样

像鸟儿一样

记得家的方向

认得人的模样

认得人的模样

却忘了飞不过时光

却忘了飞不过时光

像鸟儿一样

像鸟儿一样

活得匆匆忙忙

活得匆匆忙忙

爱得两两相望

爱得两两相望

却不知终将天各一方

多想像鸟儿一样扇动翅膀

多想像鸟儿一样扇动翅膀

展开对天空的想象

心怀梦想

心怀梦想

借着太阳的光芒 风的力量

多想像鸟儿一样目视前方

多想像鸟儿一样目视前方

拥抱这命运的无常

满怀期望

凭着自己的臂膀 风的力量

多么向前方

多么向前方

拥抱这命运的无常

满怀期望

满怀期望

凭着自己的臂膀梦的力量

凭着自己的臂膀梦的力量