比赛名次

正文索引 [隐藏]

题目描述:

有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

输入描述:

输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

输出描述:

给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。 其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

输入样例:

4 3
1 2
2 3
4 3

输出样例:

1 2 4 3

解题思路:

小米校招题。用一个vector来存放 i 战胜的队伍v[i],用loser来记录队伍 i 输掉比赛的次数loser[i],然后采用升序的优先队列来对问题进行求解。先把没输过的队伍 i 放入优先队列中,然后遍历 i 赢过的队伍 j,让loser[j]–,若loser[j]==0就把j放入优先队列中,疯狂输出直到队列为空为止。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define Up(i,a,b) for(int i = a; i <= b; i++)
#define ms(a,x) memset(a,x,sizeof(a))

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int N,M;   //N个队伍,M组数据
    while(cin >> N >> M)
    {
        vector<int> v[N+1];   //v[i]用来存放i战胜的队伍
        int loser[N+1];      //loser[i]用来存放i输掉比赛的次数
        ms(loser,0);
        while(M--)
        {
            int a,b;   //a胜了b
            cin >> a >> b;
            v[a].push_back(b);
            loser[b]++;
        }
        priority_queue<int,vector<int>,greater<int> > pq;  //升序的优先队列
        Up(i,1,N)
        {
            if(!loser[i])   //队伍i没有输过就放入优先队列
            {
                pq.push(i);
            }
        }
        int cnt = 1;
        while(!pq.empty())    //输出比赛名次
        {
            int _ = pq.top();
            pq.pop();
            printf("%d%s", _,cnt==N?"\n":" ");   //注意输出格式
            cnt++;
            int sz = v[_].size()-1;
            Up(i,0,sz)
            {
                int j = v[_][i];
                loser[j]--;
                if(loser[j] == 0)
                {
                    pq.push(j);
                }
            }
        }
    }
    return 0;
}