杭电ACM OJ 1022 Train Problem I 回溯法求出栈遍历序列 很强大

Train Problem I

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 40163    Accepted Submission(s): 15058


Problem Description
As the new term comes, the Ignatius Train Station is very busy nowadays. A lot of student want to get back to school by train(because the trains in the Ignatius Train Station is the fastest all over the world ^v^). But here comes a problem, there is only one railway where all the trains stop. So all the trains come in from one side and get out from the other side. For this problem, if train A gets into the railway first, and then train B gets into the railway before train A leaves, train A can't leave until train B leaves. The pictures below figure out the problem. Now the problem for you is, there are at most 9 trains in the station, all the trains has an ID(numbered from 1 to n), the trains get into the railway in an order O1, your task is to determine whether the trains can get out in an order O2.
                       杭电ACM OJ 1022 Train Problem I 回溯法求出栈遍历序列 很强大
 

Input
The input contains several test cases. Each test case consists of an integer, the number of trains, and two strings, the order of the trains come in:O1, and the order of the trains leave:O2. The input is terminated by the end of file. More details in the Sample Input.
 

Output
The output contains a string "No." if you can't exchange O2 to O1, or you should output a line contains "Yes.", and then output your way in exchanging the order(you should output "in" for a train getting into the railway, and "out" for a train getting out of the railway). Print a line contains "FINISH" after each test case. More details in the Sample Output.
 

Sample Input

3 123 321 3 123 312
 

Sample Output

Yes. in in in out out out FINISH No. FINISH
这题当然有简单的方法,用卡特蓝数听说是很方便的。但是我秉承着:先用暴力法做出来,再用优雅方法做出来的原则。用回溯法把整个出栈遍历序列都求出来了,非常刺激。如果想不太会回溯法的话,可以看看我上一篇文章,用回溯法求出栈遍历序列。讲的很细很细。
下面上一下效果图
杭电ACM OJ 1022 Train Problem I 回溯法求出栈遍历序列 很强大
杭电ACM OJ 1022 Train Problem I 回溯法求出栈遍历序列 很强大
下面贴出代码,对比我上一篇文章,这里增加了个操作序列的计数和输出。
public class Test {

    int length;
    int[][] allPossible;
    String[][] allOperate;

    int[] current;
    String[] operate;

    int[] inOrder;
    int[] outOrder;

    List<Integer> list;//这个当做栈

    Test(int... ints) {//123321,后面3个是要求的出栈顺序,可以不用理会
        length = ints.length / 2;

        allPossible = new int[100][length];//不想分析有几种可能,暂定100        allOperate = new String[100][length * 2];

        current = new int[length];
        operate = new String[length * 2];

        inOrder = new int[length];
        for (int i = 0; i < length; i++) {
            inOrder[i] = ints[i];
        }

        outOrder = new int[length];
        for (int i = 0; i < length; i++) {
            outOrder[i] = ints[i + length];
        }

        list = new ArrayList<>();
    }

    void back(int level, int index, int operateIndex) {//1,2带进去验证 level = 0 length = 2//最后发现index还是有必要的
        if (level == length) {
            // TODO: 2017/11/19 这里执行的是:把当前记录的出栈情况数组添加到所有情况的二维数组里,最后一起输出
            int row = -1;
            //找到第一个没有被赋值过的行,这个找到的i就是pure(纯净,未赋值过的)行号
            for (int i = 0; i < 100; i++) {
                if (allPossible[i][length - 1] == 0) {
                    row = i;
                    break;
                }
            }
            //把栈中剩余的数按出栈顺序读到结果数组里,实际上不出栈,怕影响之前的情况
            for (int i = 0; i < list.size(); i ++) {//经检验,list出栈的数据完全正确!
                int num = list.get(i);
                for (int j = length - 1; j >= 0; j --) {
                    if (allPossible[row][j] == 0) {
                        allPossible[row][j] = num;
                        break;
                    }
                }
            }
            //current里的结果也一并加上
            for (int i = 0; i < length; i++) {
                if (allPossible[row][i] == 0) {
                    allPossible[row][i] = current[i];
                } else break;
            }

            //operate进行最后处理,剩下没填满的位数,全部记成out
            for (int i = 0; i < length * 2; i ++) {
                if (operate[i] == null) {
                    operate[i] = "out";
                }
            }

            //operate全部记到allOperate二维数组里
            for (int i = 0; i < length * 2; i ++) {
                allOperate[row][i] = operate[i];
            }
            return;
        } else {//这里level0到最后一层,index指代当前操作数,如果仍在这个范围内,代表数没用完
            if (list.size() == 0) {
                list.add(inOrder[level]);

                operate[operateIndex] = "in";

                back(level + 1, index, operateIndex + 1);
                list.remove(list.size() - 1);
            } else {
                for (int i = 0; i < 2; i++) {
                    if (i == 0) {
                        list.add(inOrder[level]);

                        operate[operateIndex] = "in";

                        back(level + 1, index, operateIndex + 1);
                        list.remove(list.size() - 1);
                    } else {
                        int num = list.remove(list.size() - 1);
                        current[index] = num;

                        operate[operateIndex] = "out";

                        back(level, index + 1, operateIndex + 1);
                        list.add(num);
                    }
                }
            }
        }
    }

    void print() {
        int row = -1;
        for (int i = 0; i < 100; i++) {
            if (allPossible[i][0] == 0) {
                row = i;
                break;
            }
        }
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < length; j++) {
                System.out.print(allPossible[i][j] + " ");
            }
            System.out.println();
        }

        for (int i = 0; i < row; i++) {
            for (int j = 0; j < length * 2; j++) {
                System.out.print(allOperate[i][j] + " ");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) throws Exception {
        Test test = new Test(1, 2, 3, 4, 4, 3, 2, 1);
        test.back(0, 0, 0);
        test.print();
    }
}