栈的思想解决火车出站问题

问题1:来自算法竞赛入门6.1

某城市有一个火车站,铁轨铺设如图6-1所示。有n节车厢从A方向驶入车站,按进站顺序编号为1~n。你的任务是让它们按照某种特定的顺序进入B方向的铁轨并驶出车站。为了重组车厢,你可以借助中转站C。这是一个可以停放任意多节车厢的车站,但由于末端封顶,驶入C的车厢必须按照相反的顺序驶出C。对于每个车厢,一旦从A移入C,就不能再回到A了;一旦从C移入B就不能再回到C了。换句话说,在任意时刻,只有两种选择:A->C和C->B

样例输入:

5

1 2 3 4 5

5 4 1 2 3

6

654321

样例输出:

Yes

No

Yes

分析:

在中转站C中。车厢符合后进先出的原则,成为LIFO表,即栈,实现栈只需要一个数组stack和栈顶指针(始终指向栈顶元素)为了方便起见,这里使用的数组下标均从1开始。例如,target[1]是指目标序列中第一个车厢的编号,而stack[1]是栈底元素,这样,栈空当且仅当top=0.(否则,如果以0下标作为栈底元素起始下标,当top=0时栈仍然不为空)

晴神思路:

//火车出入站,根据晴神的思路的写法。晴神的写法就是简洁!! 
#include<cstdio>
#include<stack>
using namespace std;
const int maxn=1010;
int arr[maxn]; 
stack<int> st;
int main(){
	int n,i;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&arr[i]);
	}
	while(!st.empty()){
		st.pop();
	}
	int current=1;
	for(i=1;i<=n;i++){//这种写法对于6 Enter 6 5 4 3 2 1也是可以的! 
		st.push(i);
		while(!st.empty()&&st.top()==arr[current]){
			st.pop();
			current++;
		}
	}
	if(!st.empty()) printf("NO\n");
	else printf("YES\n");
	return 0;
} 


实现:

#include<stdio.h>
const int MAXN =1000+10;
int n,target[MAXN];
int stack[MAXN];

int main(){
	while(scanf("%d",&n)==1){
		int top=0;//top=0表示栈为空,在检测中要把其放在稍微后面一些匹配结束
		int A=1,B=1;//两个数组存放数据的初始下标 
		//输入目标数据局 
		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(top && stack[top]==target[B]){top--;B++;}
			else if(A<=n){stack[++top]=A++;} //如果上面一条不符合,就说明不出栈,继续进栈 
			else {ok=0;break;}//如果某次循环居然执行到这里,说明无法匹配,置为否,并跳出循环 
		} 	
		printf("%s\n",ok?"YES":"NO");
		/*getchar();
		getchar();*/
	}
	return 0; 
} 

问题一的解法二:(用STL栈来实现)

实现:

#include<stdio.h> 
#include<stack>//使用到栈 
using namespace std;

const int MAXN =1000+10;

int n,target[MAXN];

int main(){
	while(scanf("%d",&n)==1){
		stack<int> s;
		int A=1,B=1;
		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;} //如果上述都不符合,说明不能匹配,则置标志位为0,并且直接跳出循环 
		}
		printf("%s\n",ok?)
	} 
}


问题3:转载网址:http://blog.csdn.net/gubojun123/article/details/8036482

编号为1,2,3,4 的四列火车通过一个栈式的列车调度站,可能得到的调度结果有哪些?如果

有n 列火车通过调度站,请设计一个算法,输出所有可能的调度结果。 
【答】: 
解题思路:栈具有先进后出、后进先出的特点,因此,任何一个调度结果应该是1 ,2 ,3 ,4
全排列中的一个元素。由于进栈的顺序是由小到大的,所以出栈序列应该满足以下条件:对于
序列中的任何一个数其后面所有比它小的数应该是倒序的,例如4321 是一个有效的出栈序列,
1423不是一个有效的出栈结果(4 后面比它小的两个数 2 ,3 不是倒序)。据此, 本题可以通过
算法产生n 个数的全排列,然后将满足出栈规则的序列输出。 

依此递归定义,递归算法如下:

#include<stdio.h>
int cont=1;
void print(int str[],int n);
void perm(int str[],int k,int n)
{
	int i,temp;
	if(k==n-1)print(str,n);//k和n-1相等,即一趟递归走完 
	else{
		for(i=k;i<n;i++){//把当前节点元素与后续节点元素交换 
			temp=str[k]; str[k]=str[i]; str[i]=temp;//交换 
			perm(str,k+1,n);//把下一个节点元素与后续节点元素交换 
			temp=str[i]; str[i]=str[k]; str[k]=temp;//恢复原状	
		}
	}
}
/* 本函数判断整数序列 str[] 是否满足进出栈规则, 若满足则输出*/ 
void print(int str[],int n) 
{
	int i,j,k,l,m,flag=1,b[2]; 
	for(i=0;i<n;i++)    /* 对每个str[i] 判断其后比它小的数是否为降序序列*/ 
	{
		m=0; 
		for(j=i+1;j<n&&flag;j++){ 
 			if (str[i]>str[j])
	 		{
	 			if (m==0) b[m++]=str[j];//记录str[i]后比它小的数 
     			else 
			 	{
			 		//如果之后出现的数比记录的数还大,改变标记变量 
		 			if (str[j]>b[0]) flag=0;
		 			//否则记录这个更小的数 
        			else b[0]=str[j]; 
      			} 
      		}
		} 
	} 
	if(flag)        /* 满足出栈规则则输出 str[] 中的序列*/ 
	{   
		printf(" %2d:",cont++); //输出序号 
        for(i=0;i<n;i++) 
			printf("%d",str[i]);//输出序列 
        printf("\n"); 
    } 
} 
int main() 
{
	int str[100],n,i; 
	printf("input a int:");		/* 输出排列的元素个数*/ 
	scanf("%d",&n); 
	for(i=0;i<n;i++)			/* 初始化排列集合*/ 
		str[i]=i+1;				//第i个节点赋值为i+1 
	printf("input the result:\n"); 
	perm(str,0,n);				//调用递归 
	printf("\n"); 
	return 0; 
} 

你可能感兴趣的:(C++,算法,栈)