L3-015 球队“食物链”

某国的足球联赛中有N支参赛球队,编号从1至N。联赛采用主客场双循环赛制,参赛球队两两之间在双方主场各赛一场。

联赛战罢,结果已经尘埃落定。此时,联赛主席突发奇想,希望从中找出一条包含所有球队的“食物链”,来说明联赛的精彩程度。“食物链”为一个1至N的排列{ T
​1
​​ T
​2
​​ ⋯ T
​N
​​ },满足:球队T
​1
​​ 战胜过球队T
​2
​​ ,球队T
​2
​​ 战胜过球队T
​3
​​ ,⋯,球队T
​(N−1)
​​ 战胜过球队T
​N
​​ ,球队T
​N
​​ 战胜过球队T
​1
​​ 。

现在主席请你从联赛结果中找出“食物链”。若存在多条“食物链”,请找出字典序最小的。

注:排列{ a​1 a
​2
​​ ⋯ a
​N
​​ }在字典序上小于排列{ b
​1
​​ b
​2
​​ ⋯ b
​N
​​ },当且仅当存在整数K(1≤K≤N),满足:a
​K
​​ <b
​K
​​ 且对于任意小于K的正整数i,a
​i
​​ =b
​i
​​ 。

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

输出格式:
按题目要求找到“食物链”T
​1
​​ T
​2
​​ ⋯ T
​N
​​ ,将这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

总结

剪枝时不要想着一蹴而就,可以从开头或结尾某个好判断的点进行入手, 本题就是从存不存在可以当结尾走到起点的点了
使用printf("%d%c", a, " \n"[i==n])来输出可以方便结尾有空格的情况
对于dfs记录路径,可以开一个数组记录路径,要用到,参数传值,不需要pre数组

#include <iostream>
#include <stack>
#include <cstring>
#include <vector>
using namespace std;
const int N = 30;
int g[30][30];
int pre[30];
bool st[30];
int n;
vector<int> v[N];
bool dfs1(int u, int lev, int s)
{
	
    bool x = true;
    for (int i = 1; i <= n; i++) {
        if (!st[i] && g[i][1] == 1) x = false;
    }
    if (x) return false;
    st[u] = true;
	for (int i = 0; i < v[u].size(); i++) {
		int j = v[u][i];
		if (lev == n && s == j) {
			pre[s] = u;
			return true;
		}else {
			if (!st[j]) {
				pre[j] = u;
				if (dfs1(j, lev + 1, s)) return true;
			}
		}
	}
	st[u] = false;
	return false;
}
int main()
{
	memset(h, -1, sizeof h);
    cin >> n;
    string s;
    for (int i = 1; i <= n; i++) {
        cin >> s;
        for (int j = 0; j < n; j++) {
            if (s[j] == 'W') g[i][j + 1] = 1;
            else if (s[j] == 'L') g[j + 1][i] = 1;
        }
    }
    for (int i = 1; i <= n; i++) {
    	for (int j = 1; j <= n; j++) {
    		if (g[i][j]) v[i].push_back(j);
    	}
    }
    for (int i = 1; i <= n; i++) {
        if (g[i][1]) {
            judge[i] = true;
            cont++;
        }
    }
    bool flag = true;
    for (int i = 1; i <= n; i++) {
        memset(st, false, sizeof st);
        if (dfs1(i, 1, i)) {
            flag = false;
            stack<int> k;
            int f = pre[i];
            while (f != i) {
                k.push(f);
                f = pre[f];
            }
            k.push(i);
            bool check = false;
            while (!k.empty()) {
                if (!check) {
                    cout << k.top();
                    check = true;
                }else cout << " " << k.top();
                k.pop();
            }
            break;
        }
    }
    if (flag) cout << "No Solution" << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值