bzoj1189: [HNOI2007]紧急疏散evacuate(二分+最大流+宽搜)
来源:互联网 发布:php什么时候用双引号 编辑:程序博客网 时间:2024/04/29 10:40
题目传送门
这道题真的是一道好题啊!!!!
表示做了两个小时。。
bzoj的数据是真的强(pi)。
一开始yy了个图结果发现错了。
上网看了看题解。按照构图敲了个代码。
错了!!!
听说被一组神数据卡掉了。
数据如下。
4 5
XXDXX
XX.XX
X…X
XXDXX
按照题解的方法跑出来答案是2但是手算是3。
很无语,只好自己yy了。。
所以想到了拆点。
建图是这样的:
st连接每个空地,流量为1(表示每个空地一开始有一个人)
每个人去找每一个门。
假设当前这个人距离某一个门为t。
如果t<=当前规定时间的话。很明显可以到达。所以连边。
那么他走过去就需要t的时间。
但是呢,因为同一时间不能有两个人通过同一个门。所以他有可能就是t+1的时间到的。
也有可能是t+2时间到的,还有其他的可能。
所以说我们把每一个门都拆成若干个点。
第一个点代表这个门在第1个时间点里到的人。
第二个点表示这个门在第2个时间点里到的人。
以此类推。
然后每一个门的点都去连接ed,容量为1。
表示的是这个门在这个时间点里只能有一个人通过(因为我已经拆点了嘛)
建好图跑最大流,最大流量等于在这个时间限制下最多能通过多少人。
如果全部都可以通过那么继续往小的二分。
代码实现:
#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;struct node { int x,y,c,next,other;}a[2100000];int len,last[6100000];void ins(int x,int y,int c) { int k1,k2; len++;k1=len; a[len].x=x;a[len].y=y;a[len].c=c; a[len].next=last[x];last[x]=len; len++;k2=len; a[len].x=y;a[len].y=x;a[len].c=0; a[len].next=last[y];last[y]=len; a[k1].other=k2; a[k2].other=k1;}int st,ed,head,tail,list[210000],h[210000];bool bfs() { memset(h,0,sizeof(h));h[st]=1; head=1;tail=2;list[1]=st; while(head!=tail) { int x=list[head]; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(h[y]==0&&a[k].c>0) { h[y]=h[x]+1; list[tail++]=y; if(tail==ed+1) tail=1; } } head++; if(head==ed+1) head=1; } if(h[ed]==0) return false; return true;}int findflow(int x,int f) { if(x==ed) return f; int s=0,t; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(a[k].c>0&&h[y]==h[x]+1&&s<f) { t=findflow(y,min(a[k].c,f-s)); s+=t;a[k].c-=t;a[a[k].other].c+=t; } } if(s==0) h[x]=0; return s;}int d[31][31][31][31]; //d[i][j][x][y]表示(i,j)到(x,y)的距离struct dian { int x,y;}llist[410];int n,m;bool v[31][31],map[31][31];int dx[5]={-1,0,1,0};int dy[5]={0,1,0,-1};bool pd(int x,int y) { if(x<1||y<1||x>n||y>m) return false; return true;}char ss[31][31];void bfs(int stx,int sty) { //求出(stx,sty)这个位置到其他点的距离 head=1;tail=2;llist[1].x=stx;llist[1].y=sty; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) d[stx][sty][i][j]=999999999; d[stx][sty][stx][sty]=0; memset(v,false,sizeof(v));v[stx][sty]=true; while(head!=tail) { dian tno=llist[head]; int x=tno.x,y=tno.y; for(int i=0;i<=3;i++) { int tx=x+dx[i],ty=y+dy[i]; if(d[stx][sty][tx][ty]>d[stx][sty][x][y]+1&&map[tx][ty]==true&&pd(tx,ty)==true) { //满足条件才可以走。 d[stx][sty][tx][ty]=d[stx][sty][x][y]+1; if(v[tx][ty]==false&&ss[tx][ty]!='D') { //遇到一个门就要进去,不能再去别的地方了,所以门是不可以进入队列的。 v[tx][ty]=true; llist[tail].x=tx;llist[tail++].y=ty; } } } head++; }}bool f[410][410];struct Dian { int x,y;}t[1100];int main() { scanf("%d%d",&n,&m); memset(map,true,sizeof(v)); int s=0,A=0; for(int i=1;i<=n;i++) { scanf("%s",ss[i]+1); for(int j=1;j<=m;j++) { if(ss[i][j]=='X') map[i][j]=false; if(ss[i][j]=='D') //t数组存D的信息 t[++s].x=i,t[s].y=j; if(ss[i][j]=='.') A++; //A表示有多少块空地 } } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(ss[i][j]=='.') bfs(i,j); //求每一块空地到别的地方的距离 int l=1,r=400,mid,ans=-1; //点的编号我是这样排的。空地为1~n*m,门为n*m+1~n*m+mid*s //因为s表示有多少个门,每个门又拆成了若干个点(mid) while(l<=r) { mid=(l+r)/2; //mid就是二分的时间限制 len=0;memset(last,0,sizeof(last)); st=n*m+mid*s+1,ed=st+1; //每次的st和ed for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(ss[i][j]=='.') ins(st,(i-1)*m+j,1); //st到每块空地容量为1 int sss=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(ss[i][j]=='.') for(int k=1;k<=s;k++) { Dian D=t[k]; int dd=d[i][j][D.x][D.y]; //距离等于时间。 while(dd<=mid) { ins((i-1)*m+j,n*m+s*(dd-1)+k,1); //每一种可能都要连边 dd++; } } for(int i=n*m+1;i<=n*m+mid*s;i++) //每个门都去连ed ins(i,ed,1); int sum=0; while(bfs()==true) sum+=findflow(st,999999999); if(sum==A) { //如果最后通过的人数等于空地数那也就是合法了。 r=mid-1;ans=mid; } else l=mid+1; } if(ans==-1) printf("impossible\n"); else printf("%d\n",ans); return 0;}
这道题真是好题,考验构图能力。
力荐!!!
阅读全文
0 0
- bzoj1189: [HNOI2007]紧急疏散evacuate(二分+最大流+宽搜)
- [BZOJ1189][HNOI2007]紧急疏散evacuate(bfs+二分+最大流)
- 【BZOJ1189】【HNOI2007】紧急疏散evacuate 二分答案+最大流check
- 【BZOJ1189】[HNOI2007]紧急疏散evacuate【最大流】【二分】
- [BZOJ1189][HNOI2007]紧急疏散evacuate(二分+网络流)
- bzoj1189 [HNOI2007]紧急疏散evacuate(二分答案+bfs+最大流判是否满流)
- 【bzoj1189】[HNOI2007]紧急疏散evacuate 二分+dinic
- HNOI2007.BZOJ1189.紧急疏散(最大流 && 二分)
- BZOJ1189【HNOI2007】紧急疏散evacuate <二分答案+网络流>
- bzoj1189 [HNOI2007]紧急疏散EVACUATE spfa+网络流+二分
- 最大流——BZOJ1189/Luogu3191 [HNOI2007]紧急疏散evacuate
- bzoj1189 [HNOI2007]紧急疏散evacuate
- bzoj1189: [HNOI2007]紧急疏散evacuate
- BZOJ1189 [HNOI2007]紧急疏散evacuate
- 【bzoj1189】[HNOI2007]紧急疏散evacuate
- bzoj1189: [HNOI2007]紧急疏散evacuate
- BZOJ1189: [HNOI2007]紧急疏散evacuate
- BZOJ 1189 HNOI2007 紧急疏散evacuate 二分答案+最大流
- 使用三种不同核函数配置的支持向量机(回归)模型对美国波士顿地区房价进行预测
- MyISAM和InnoDB的索引实现
- Android消息机制
- dede织梦系统怎样导出后台的文章或自定义模型中的数据到excel,并且不出现乱码
- centos7下编译安装nginx
- bzoj1189: [HNOI2007]紧急疏散evacuate(二分+最大流+宽搜)
- 大数(转自http://blog.csdn.net/zz_1215/article/details/6716132)
- chcon命令详解
- C++笔记记录Ⅲ 继承与多态
- 【Tensorflow】tf.nn.depthwise_conv2d如何实现深度卷积?
- 自定义ActionBar、Toolbar布局(解决自定义ActionBar布局左边始终有一点边距的问题)
- 安卓多用户笔记-跨用户空间数据迁移
- Android中已经添加权限,依然提示缺少权限,此时你需要添加动态权限
- 简易织梦DEDECMS自定义表单导出为excel功能