【题解】 对决

题目描述

【题目描述】
    已知n个人(编号为1..n)进行了m轮对决,且给出这m轮对决的结果。
    请根据这m轮对决的结果,计算出可以确定多少人的最终排名。
【输入格式】
    第一行两个整数n,m表示总共有n个人,m场对决.
    以下m行,每行两个整数ai,bi,表示ai号的人战胜了bi号的人.
    其中,1<=n<=100,1<=m<=4500。
【输出格式】
    一个数,表示能够确定名次的人的数量.
【样例】
    输入数据 1
        5 5
        4 3
        4 2
        3 2
        1 2
        2 5
    输出数据 1
        2

思路

该题主要考察:Floyd传递闭包

显而易见,对决结果具有传递性。举个例子,1号比2号强,2号比3号强,那么1号比3号强。
所以,首先用Floyd传递闭包传递出所有人两两之间的强弱关系。

然后对于每个人,一共 \(n\) 个人,除去他自己剩下 \(n - 1\) 个人,只要这 \(n - 1\) 个人与他都有强弱关系,就可以确定他的排名。
拿样例举个例子:2号比1号弱,比3号弱,也比4号弱,又比5号强,所以比2号强的有1号、3号、4号,共3个,比他弱的有5号一个。比他强的和比他弱的正好4个人,所以就可以确定2号的排名。

代码

#include <bits/stdc++.h>
using namespace std;

int n, m;
bool a[105][105]; // a[i][j] 记录 i是否比j强。true 表示 i比j强;false则不一定,需要判断 a[j][i]

// Floyd 传递闭包
void Floyd()
{
    for (int k = 1; k <= n; k ++ )
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= n; j ++ )
                if (a[i][k] && a[k][j]) a[i][j] = 1; // 如果i比k强,k比j强,则i比j强
}

int main()
{
    scanf("%d%d", &n, &m);
    while (m -- )
    {
        int x, y; scanf("%d%d", &x, &y);
        a[x][y] = 1; // 记录 x比y强
    }

    Floyd();

    int ans = 0;
    for (int i = 1; i <= n; i ++ )
    {
        bool flag = true;
        for (int j = 1; j <= n; j ++ )
        {
            if (i == j)  continue; // 比较时除去自己
            if (!a[i][j] && !a[j][i]) // 如果i不比j强,j也不比i强,就代表i与j的强弱关系未知
            {
                flag = false; // 记录 i 的强弱关系并不是全部已知
                break;
            }
        }
        if (flag) ans ++ ;  // 如果 i 的强弱关系全部已知,累加答案
    }
    printf("%d\n", ans);

    return 0;
}
posted @ 2024-08-15 08:48  T_泓  阅读(21)  评论(0编辑  收藏  举报