PTA 7-1 列车厢调度(c语言实现)【详解】

博客详细介绍了PTA的7-1列车厢调度问题,提供了一种C语言解决方案。文章阐述了问题背景、规则,并给出了两个输入样例及其对应的调度操作序列。在无法调度的情况下,程序会输出特定提示。

PTA 7-1 列车厢调度
1 ====== <–移动方向
/
3 =====

2 ====== -->移动方向
大家或许在某些数据结构教材上见到过“列车厢调度问题”(当然没见过也不要紧)。今天,我们就来实际操作一下列车厢的调度。对照上方的ASCII字符图,问题描述如下:

有三条平行的列车轨道(1、2、3)以及1-3和2-3两段连接轨道。现有一列车厢停在1号轨道上,请利用两条连接轨道以及3号轨道,将车厢按照要求的顺序转移到2号轨道。规则是:

每次转移1节车厢;
处在1号轨道的车厢要么经过1-3连接道进入3号轨道(该操作记为"1->3"),要么经过两条连接轨道直接进入2号轨道(该操作记为"1->2");
一旦车厢进入2号轨道,就不可以再移出该轨道;
处在3号轨道的车厢,只能经过2-3连接道进入2号轨道(该操作记为"3->2");
显然,任何车厢不能穿过、跨越或绕过其它车厢进行移动。
对于给定的1号停车顺序,如果经过调度能够实现2号轨道要求的顺序,则给出操作序列;如果不能,就反问用户 Are(你) you(是) kidding(凯丁) me(么)?

输入格式:
两行由大写字母组成的非空字符串,第一行表示停在1号轨道上的车厢从左到右的顺序,第二行表示要求车厢停到2号轨道的进道顺序(输入样例1中第二行CBA表示车厢在2号轨道的停放从左到右是ABC,因为C最先进入,所以在最右边)。两行字符串长度相同且不超过26(因为只有26个大写字母),每个字母表示一节车厢。题目保证同一行内的字母不重复且两行的字母集相同。

输出格式:
如果能够成功调度,给出最短的操作序列,每个操作占一行。所谓“最短”,即如果1->2可以完成的调度,就不要通过1->3和3->2来实现。如果不能调度,输出 “Are you kidding me?”

输入样例1:
ABC
CBA
输出样例1:
1->3
1->3
1->2
3->2
3->2
输入样例2:
ABC
CAB
输出样例2:
Are you kidding me?

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define STACK_INIT_SIZE 26    //题目已经给出最大不会超过26
typedef char SElemType;        //设置元素类型为char
typedef int Status;           //函数返回类status为int型
typedef struct{               //定义栈的结构类型
    SElemType *base; //定义栈底指针
    SElemType *top; //定义栈顶指针
    int stacksize;  //记录栈的长度
}sqstack; //命名为sqstack
Status InitStack(sqstack &s){ //定义栈的初始化
    s.base=(SElemType *) malloc(STACK_INIT_SIZE * sizeof(SElemType));   //一个元素类型(char)的空间,作为栈底
    s.top=s.base; //栈顶等于栈底
    s.stacksize=STACK_INIT_SIZE; //先设置栈的长度为26
    return 1;
}

Status Push(sqstack &s,SElemType e){ //定义入栈
    *s.top++=e; //为栈顶元素赋值,并把栈顶指针后移
    return 1;
}

Status GetTop(sqstack s,SElemType &e){ //定义获取栈顶元素
    if(s.top==s.base) return 0; //如果栈已经空了,返回0
    e=*(s.top-1); //返回栈顶指针前一个元素(栈顶指针指向的是最后一个元素下一个位置)
    return 1;
}

Status Delete(sqstack &s){ //删除栈顶元素
    s.top--; //直接将栈顶指针下移即可
    return 1;
}

Status StackLength(sqstack s){ //返回栈的元素个数
    return s.top-s.base; //栈顶减去栈底即为元素个数
}
int main(void){
    int flag[100],k=0;   //用flag记录每行输出对应的标志及其顺序,如13对应1->3,
       //因为对比前面的元素的时候不知道后面的序列是否能够调度,如果后面的序列不能调度,直接控制不输出flag数组即可
    sqstack s1,s2,s3; //声明三个栈,s1一号轨道,s2是二号轨道,s3是三号轨道
    InitStack(s1);InitStack(s2);InitStack(s3);//初始化三个栈
    char t1[26],t2[26];         //用来将输入字符记录到t1,t2两个数组中,以供入栈
    int j;  //记录给出的字符串长度
    scanf("%s",t1);
    j=strlen(t1);
    for(int i=j-1;i>=0;i--){
        Push(s1,t1[i]);    //由于题目需要,要倒着入栈;
    }                        //s1入栈完毕
    scanf("%s",t2);
    j=strlen(t2); 
    for(int i=j-1;i>=0;i--){
        Push(s2,t2[i]);    //由于题目需要,要倒着入栈;
    }                        //s2入栈完毕
    SElemType e1,e2,e3; //声明三个元素,e1用来从轨道1对应的栈中取元素,e2用来从轨道2中取出元素,e3为三号轨道
    while(StackLength(s1)>=1){ //循环比较栈1(轨道1)和栈2(轨道2)的元素
        GetTop(s1,e1);  //从栈1(轨道1)中取出栈顶元素
        GetTop(s2,e2);  //从栈2(轨道2)中取出栈顶元素
        if(e1==e2){  //如果相等的话,直接进入轨道2即可,不需要通过轨道3
            flag[k]=12;    //记录此时应该输出的内容(假设后面的序列不会出现无法调度的情况)12即1->2
            k++;
            Delete(s1);//删除已经调度完成的两个元素
            Delete(s2);
            while(StackLength(s3)!=0){ //每一次完成从1->2的调度后,都要往前检查是否有满足3->2的调度的序列
                GetTop(s3,e3); //从栈3(轨道3)中取出元素
                GetTop(s2,e2); //从栈2(轨道2)中取出元素
                if(e3==e2){  //判断是否满足相等
                    flag[k]=32;    //记录下应该进行的调度,32即3->2
                    k++;
                    Delete(s2); //删除已经调度完成的元素
                    Delete(s3);
                }
                else break;
            }
        }
        else //如果栈1(轨道1)与栈2(轨道2)的元素不相等,先把栈1的元素放进栈3
        {
            Push(s3,e1);
            Delete(s1);
            flag[k]=13;           //记录下应进行的操作,13即1->3
            k++;
        }
    }
    if(StackLength(s2)!=0) printf("Are you kidding me?"); //如果到最后栈2的元素依然非空,则说明不能完成调度
    else  //如果最后栈2已经空了,说明能够完成调度,此时只要依次输出flag数组内记录的内容
        for(int i=0;i<=k-1;i++){
            if(flag[i]==12) printf("1->2\n"); //对flag数组内记录的内容判断并输出
            if(flag[i]==13) printf("1->3\n");
            if(flag[i]==32) printf("3->2\n");
        }
}

感悟:
1.思路好想
2.代码好写
3.找bug很难。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值