【紫书】系列 UVA 514 铁轨(Rails)ACM/ICPC CERC 1997

问题描述:

    某城市有一个火车站,铁轨铺设如下图所示。有n节车厢从A方向驶入车站,按进站顺序编号为1~n。你的任务是判断是否能让他们按照某种特定的顺序进入B方向的铁轨并驶出车站。例如,出站顺序(5 4 1 2 3)是不可能的,但(5 4 3 2 1)是可能的。

为了重组车厢,你可以借助中转站C。这是一个可以停放任意多节车厢的车站,但由于末端封顶,驶入c的车厢必须按照相反的顺序是出C。对于每个车厢,一旦从A移到c,就不能再回到A,一旦从C移入到B,就不能再回到C。换句话说,在任意时刻,只有两种选择:A->c和C->B。

【分析】

1、首先,在中转站C处,车厢符合后进先出的原则,因此C是一个栈。

2、从题目可以看出从A到B的匹配不好实现,那么可以从B来推出A,那么B处就要先存储火车车厢节元素

3、要想使AB两处的火车次序符合题意,可以分析出有三种情况:

                                                                                (1)当B处当前所指的元素不等于A处输入的车厢元素并且也不等于C的栈顶元素时,则将A处输入的车厢节压入栈(C)中;

                                                                                (2)当A处输入的车厢节等于B处时,则可直接进行下一次操作,A、B都加一;

                                                                                (3)当C栈的栈顶车厢节数等于B处并且栈不为空时,那么弹出C栈中的此元素,并且B加一,以进行下一次操作;

                                                                                (4)当上述三个条件都不满足时,则退出while输入循环。

4、当A处的输入元素是1 2 3 4 5,那么B处该输出 5 4 3 2 1。那么我们来看一下想法的正确性,演练一下

(1) B处此时已经输入 5 4 3 2 1,B的第一个元素是5,现在开始输入A处元素,第一次循环,输入1,1!=5,那么符合情况(1),则将1压入栈C中;

                                                                                                                                第二次循环,输入2,2!=5,仍旧符合情况(1),则将2压入栈C中;

                                                                                                                                第三、四次循环依旧如此,则栈C中此时从栈顶到栈底依次存着4 3 2 1;

(2)第五次循环,输入5,5==5,符合情况(2),那么A++,B++,此时B指向4;

(3)此时A已经为空,C不为空,那么比较C与B中元素,发现C栈顶元素4==B指向元素4,那么就符合情况(3),弹出栈顶的4,栈顶指针后移,B指针后移,再次进行比较;

                                                                      第二次比较,发现C栈顶元素3==B指向元素3,仍旧符合情况(3),弹出栈顶的3...直到最后弹出栈底的1与B作比较,仍旧符合,则判断结束,退出while循环。

5、由于不能直接输入A的车厢节数,我们可以使用A++来让程序帮我们进行每一次的输入。

代码:

#include <cstdio>
#include <stack>
using namespace std;
const int MAXN=1000+10;

int n,target[MAXN];

int main(){
 while (scanf("%d",&n)==1){//n是车厢的节数
  stack<int> s;
  int A=1,B=1;
  printf("输入火车从B车站出站的顺序:") ;
  for(int i=1;i<=n;i++)
  scanf("%d",&target[i]);
  int ok=1;
  while(B<=n){
   if(A==target[B])
       {A++;B++;}
   else if( !s.empty() && s.top()==target[B] ) {s.pop() ; B++;}
   else if (A<=n) s.push(A++);
   else {ok=0; break;} 
   printf("%d--%d ",A,B);
   printf(" ");
  }
  printf("%s ",ok?"Yes":"No");
 }
 return 0;
}

【显示结果】

【总结】

1、此代码貌似只能应用于当车厢节数从1开始的数据,<不知道是不是我没理解对题意:>>当我试着输入5节车厢数,但是B处 的车厢为7 6 5 4 3,结果显示为下图

(那么我就考虑可以自己输入A车厢的初始值,然后A++再与B比较,自己玩玩)但是这样在真正做题时会超时,并且,竞赛的题目应该是不会有交互性的。所以紫书上的代码合理,让程序自行来加A的车厢数(每种情况都有的A++)

2、刚开始接触 这类题,刚看题目时没看懂,就跑去网上搜代码和讲解,玩了两天还是不懂,不知道这道题的解题思路究竟是什么、在哪,今天再一接触,决定自己模拟一下火车进站出站的匹配,恍然大悟。下午写博客时又仔细研究了一下代码,确实还是有些小细节自己当时没有注意到。

原文地址:https://www.cnblogs.com/zx-zhang/p/7738269.html