Emergency Evacuation(贪心)
Posted li-jia-hao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Emergency Evacuation(贪心)相关的知识,希望对你有一定的参考价值。
题目描述(中文版)
紧急疏散
时间限制:3秒
日本政府计划到2020年将入境游客人数增加到4000万,到2030年增加到6000万。不仅要增加游客的吸引力,而且要进一步发展旅游基础设施对于实现这一数字是必不可少的。
运输方面的一种可能的改进是提供极长和/或较宽的汽车,一次可搭载多名乘客。但是,太大的汽车可能需要太长时间才能在紧急情况下疏散所有乘客。请您帮助估计所需的时间。
假定汽车具有以下座椅布置。
•中央过道直通汽车,直接连接到汽车后部中央的紧急出口门。
•乘客座位数相同的行位于过道的两侧。
要求的粗略估算基于简单的逐步模型。最初,所有乘客都坐在不同的座位上,他们可以在每个步骤中进行以下任一动作。
•座位上的乘客可以朝过道移动到相邻的座位。与过道相邻的座位上的乘客可以直接向侧面移动到过道。
•过道上的乘客可以向后移动一排座位。如果乘客在紧急出口的前面,即在最后面的座位排,他/她可以下车。
要移动的座位或过道位置必须为空;或者在该步骤之前没有其他乘客在这里,或者该乘客通过在同一步骤中移至另一个位置来清空座位。当两个或两个以上的乘客满足同一位置的条件时,他们中只有一个可以移动,而其他人则保持在原来的位置等待。
图C.1的最左图描绘了样本输入1中给出的小型汽车的座椅布置。该汽车有五排座椅,在过道两侧各有两个座椅,共二十个。还显示了船上七名乘客的初始位置。
图C.1的另外两个图显示了第一步和第二步之后乘客的可能位置。乘客的移动由粗箭头指示。请注意,前排座位中的两名乘客必须在第一步中等待空缺,而第二排中的一名乘客必须在下一步中等待。
您的任务是编写一个程序,在给定座位安排和乘客初始位置的情况下,为所有乘客下车提供尽可能少的步骤。
错误的思路分析
我上来看到这道题的第一印象就是模拟人们下车的过程,当时没有考虑时间效率,就调出来了一个极其难看的代码,跑的还贼慢。大家感兴趣的可以看看我的笨蛋思路。
1. 在考虑下车时,由于开始时过道两边可能都有人坐,我们就要考虑是左边先下还是右边先进过道的问题
我们便可以假设有如图的一种情况,我们设他们相邻过道上的位置距离出口d,则三个点无论以什么样的顺序出,最终耗时都为(d+1)+(d+1)+(d+2)即3d+4个单位时间,所以相邻过道两边的先后进入过道的顺序与最终答案无关。
2. 若出现如下图的情况,红色的人应该先插入过道还是待一列人走完后从末尾跟着走(有颜色代表有人)
我们可以假设红色在前面,则该五个人出去所需的总时间为7个单位时间,而让红色跟在后面,则需要8个单位时间,故如果在过道边坐着的人如果可以进入过道的话就让优先进入过道。
则我们最终模拟的顺序为先让能进入过道的人先进过道,再让中间的还没动过的人向下走,最后往中间移得动的人向中间动,这是一次移动,最后计数即可。
弄上代码
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int N=500; 5 const int maxn=N*N; 6 struct People{ //People保存每个人的位置(x,y),是否下车(chu) 7 int x,y; // 本轮是否移动(ok) 8 bool chu,ok; 9 }pe[N]; 10 int a[N][N]; //存储车的平面图. 11 int id[N][N]; //存储每个位置的编号 12 int r,s,p,mid; 13 int ans=0; 14 int main(){ 15 scanf("%d%d%d",&r,&s,&p); 16 int mid=s+1; 17 for(int i=1;i<=p;++i){ 18 int x,y; 19 scanf("%d%d",&x,&y); 20 if(y>=mid) y++; 21 a[x][y]=1; 22 id[x][y]=i; 23 pe[i].x=x;pe[i].y=y; 24 } 25 int cnt=p; 26 while(cnt){ 27 for(int i=1;i<=p;++i) //每轮更新 28 pe[i].ok=0; 29 for(int i=1;i<=p;++i){ //可以进过道的进过道 30 if(pe[i].y==s&&!a[pe[i].x][mid]){ 31 int x=pe[i].x,y=pe[i].y; 32 a[x][y]=0;a[x][y+1]=1; 33 pe[i].y++;id[x][y+1]=id[x][y];id[x][y]=0; 34 pe[i].ok=1; 35 } 36 if(pe[i].y==s+2&&!a[pe[i].x][mid]){ 37 int x=pe[i].x,y=pe[i].y; 38 a[x][y]=0;a[x][y-1]=1; 39 pe[i].y--;id[x][y-1]=id[x][y];id[x][y]=0; 40 pe[i].ok=1; 41 } 42 } 43 for(int i=r;i>=1;--i){ //过道可以往下走的往下走. 44 int t=id[i][mid]; 45 if(!t||pe[t].chu) continue; 46 if(pe[t].ok) continue; 47 if(i==r){ 48 pe[t].chu=true;a[i][mid]=0; 49 cnt--; 50 } 51 else if(a[i+1][mid]) continue; 52 a[i+1][mid]=1;a[i][mid]=0; 53 pe[t].x=i+1;pe[t].ok=1; 54 id[i+1][mid]=id[i][mid];id[i][mid]=0; 55 } 56 for(int i=1;i<=p;++i){ //两边可以向中间靠的向中间靠. 57 int x=pe[i].x,y=pe[i].y; 58 if(pe[i].chu) continue; 59 if(y==mid) continue; 60 if(y<mid){ 61 if(a[x][y+1]) continue; 62 a[x][y+1]=1;a[x][y]=0;id[x][y+1]=id[x][y];id[x][y]=0; 63 pe[i].ok=true;pe[i].y=y+1; 64 while(a[x][y-1]&&!pe[id[x][y-1]].ok){ 65 if(y>=mid||y<1) break; 66 a[x][y-1]=0;a[x][y]=1;id[x][y]=id[x][y-1];id[x][y-1]=0; 67 pe[id[x][y]].ok=true;pe[id[x][y]].y++; 68 y--; 69 } 70 } 71 if(y>mid){ 72 if(a[x][y-1]) continue; 73 a[x][y-1]=1;a[x][y]=0;id[x][y-1]=id[x][y];id[x][y]=0; 74 pe[i].ok=true;pe[i].y--; 75 while(a[x][y+1]&&!pe[id[x][y+1]].ok){ 76 if(y<=mid||y>2*s+1) break; 77 a[x][y+1]=0;a[x][y]=1;id[x][y]=id[x][y+1];id[x][y+1]=0; 78 pe[id[x][y]].ok=true;pe[id[x][y]].y--; 79 y++; 80 } 81 } 82 } 83 ans++; //统计次数 84 } 85 printf("%d ",ans); 86 return 0; 87 }
如果你这样写了,恭喜你,由于超时你一个点都过不了。
下面才是正确思路及写法
我们可以逆序考虑,既然求下车的最大时间,我们可以转化为每个人都在车下,先后上车到他的座位,求出上车最慢的等待时间即可。每个人的时间开销为上车时间+等待时间,则根据贪心的思想,我们可以对每个人的上车时间进行排序,时间花销大的先上车,最后将每个人的上车时间和等待时间之和取最大值即可。(每个人的时间开销即从座位到出口的距离)
附上代码
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=500*500; 6 struct People{ //保存每个人的位置,及距出口的距离. 7 int r,c; 8 int d; 9 }pe[N]; 10 bool cmp(People a,People b){ 11 return a.d>b.d; 12 } 13 int main(){ 14 int r,s,p; 15 scanf("%d%d%d",&r,&s,&p); 16 for(int i=1;i<=p;++i){ 17 scanf("%d%d",&pe[i].r,&pe[i].c); 18 if(pe[i].c>s) //计算距离,横向加竖向. 19 pe[i].d=(pe[i].c-s)+(r-pe[i].r+1); 20 else 21 pe[i].d=(s-pe[i].c+1)+(r-pe[i].r+1); 22 } 23 sort(pe+1,pe+1+p,cmp); 24 int k=1; //k由于计算每个人的等待时间 25 int max_time=pe[1].d; 26 for(int i=2;i<=p;++i){ 27 if(pe[i].d+k>max_time) 28 max_time=pe[i].d+k; //计算最大时间开销 29 k++; 30 } 31 printf("%d ",max_time); 32 return 0; 33 }
正确写法及思路来自https://blog.csdn.net/qq_40534166/article/details/88894175?depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1&utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1
以上是关于Emergency Evacuation(贪心)的主要内容,如果未能解决你的问题,请参考以下文章
[bzoj3371][poj2009][Usaco2004 Mar]Moo University - Emergency Pizza Order 定制比萨饼