PAT L3-015 ---- 球队“食物链”(DFS)

球队“食物链”
某国的足球联赛中有N支参赛球队,编号从1至N。联赛采用主客场双循环赛制,参赛球队两两之间在双方主场各赛一场。
联赛战罢,结果已经尘埃落定。此时,联赛主席突发奇想,希望从中找出一条包含所有球队的“食物链”,来说明联赛的精彩程度。“食物链”为一个1至N的排列{ T1,T2, …,TN },满足:球队T1战胜过球队T2,球队T2战胜过球队T3,……,球队T(N-1)战胜过球队TN,球队TN战胜过球队T1。
现在主席请你从联赛结果中找出“食物链”。若存在多条“食物链”,请找出字典序最小的。
注:排列{ a1,a2,…,aN }在字典序上小于排列{ b1,b2, … ,bN },当且仅当存在整数K(1 <= K <= N),满足:aK < bK且对于任意小于K的正整数i,ai=bi。

输入格式:
输入第一行给出一个整数N(2 <= N <= 20),为参赛球队数。随后N行,每行N个字符,给出了NxN的联赛结果表,其中第i行第j列的字符为球队i在主场对阵球队j的比赛结果:“W”表示球队i战胜球队j,“L”表示球队i负于球队j,“D”表示两队打平,“-”表示无效(当i=j时)。输入中无多余空格。

输出格式:
按题目要求找到“食物链”T1,T2 ,…,TN,将这N个数依次输出在一行上,数字间以1个空格分隔,行的首尾不得有多余空格。若不存在“食物链”,输出“No Solution”。

输入样例1:

5
-LWDW
W-LDW
WW-LW
DWW-W
DDLW-

输出样例1:

1 3 5 4 2

输入样例2:

5
-WDDW
D-DWL
DD-DW
DDW-D
DDDD-

输出样例2:

No Solution

学校去年举办的程序设计大赛,当时大一只做出来几个水题,后面的大题根本看不懂,时隔将近一年想回去试试能不能AC了那些题。。。。。。事实证明,还有些差距。下面将给出我的思路。

无题解纯自己思考,看完题目想到了TSP问题,算法还算是给了我一定的思绪,我记得好像可与用dfs()解决。
但是做的过程中发现,输入的数据会发生一些问题,仔细排查后原来是由于nexLine()会读取上一个回车导致的,之前也遇到过,只是当时搞明白之后就没有再碰。
接下来就是自己手写dfs(),第一次尝试自己写,而看着模板,但是发现好几个点过不去,比如如何确定跳出时机,如何实现字典序输出,我在主函数写f(1)这不是只能是1开头了。很迷。下面的代码运行不出结果。

import java.util.Scanner;

public class Main {
    static String[][] str;
    static int n;
    static int cnt = 0;
    static boolean[][] vis;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        str = new String[n + 1][n + 1];
        vis = new boolean[n + 1][n + 1];
        /**
         * 注意nextLine()会读取上一个回车
         * */       
        for (int i = 0; i < n+1; i++) {
            String s = in.nextLine();
            str[i] = s.split("");
        }
        f(1);
//      for (int i = 1; i < n+1; i++) {
//          for (int j = 1; j < n+1; j++) {
//              System.out.print(str[i][j] + " ");
//          }
//          System.out.println();
//      }
    }
    private static void f(int m) {
        // TODO Auto-generated method stub
        if (cnt > m) {

        }
        for (int i = 1; i < n+1; i++) {
            for (int j = 1; j < n+1; j++) {
                if (str[i][j].equals("W")) {
                    vis[i][j] = true;
                    f(j);
                }
            }
        }
    }
}

接下来看题解,一开始就发现自己做了一个非常繁琐的操作进行存储数据,而题解的做法是直接用boolean数组存,‘W’是true,‘L’是false,巧妙不少。结尾输出的方式也是巧妙,第一个不打印空格,之后都在打印之前加一个空格,可以巧妙的避免结尾的空格影响AC。
这道题跟单纯的TSP问题区别就在于TSP是对于无向赋权图来说找出最短的哈密顿回路,而这道题是对于有向无权图来说的(为什么是有向的,这是因为主客场制出现A在主场赢了B,A在客场也赢了B的情况)。当然剪枝之后效率会更好,但是蒟蒻的我还是不要把自己越搞越迷糊的好。

import java.util.Scanner;

public class Main {
    static boolean[][] a;
    static int n;
    static int cnt = 0;
    static int flag = 0;
    static int[] res;
    static boolean[] vis;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        a = new boolean[n + 1][n + 1];
        vis = new boolean[n + 1];
        res = new int[n + 1];
        /**
         * 注意nextLine()会读取上一个回车
         * */       
        for (int i = 0; i <= n; i++) {
            String s = in.nextLine();
            for (int j = 0; j < s.length(); j++) {
                if (s.charAt(j) == 'W') {
                    a[i][j+1] = true;
                } 
                if (s.charAt(j) == 'L'){
                    a[j+1][i] = true;
                }
            }
        }


        f(1, 1);
        if (flag == 1) {
            for (int i = 1; i <= n; i++) {
                System.out.print(i == 1 ? "" : " ");
                System.out.print(res[i]);
            }
        } else {
            System.out.println("No Solution");
        }

    }
    private static void f(int cur, int num) {
        if (flag == 1) {
            return;
        }
        res[cur] = num;
        if (cur == n && a[num][1] == true) {
            flag = 1;
            return;
        }
        if (cur == n) {
            return; 
        }

        vis[num] = true;
        for (int i = 1; i <= n; i++) {
            if (vis[i] == false && a[num][i] == true) {
                f(cur + 1, i);
            }
        }
        vis[num] = false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值