1.分析
这道题目是学习了拓扑排序之后的习题,所以自然而然往拓扑排序思考。要求是赢得队伍排名一定在输的队伍之前。把队伍看成结点,如果A队赢了B队,就连一条有向边<A,B>,这样就建立起了图论模型。然后就能发现题目是要求输出一个图的拓扑排序。题目中要求输出字典序最小的拓扑排序,那么只需要每次优先输出入度为零的、编号最小的点就可以了。有些贪心算法的思路在里面。
2.AC代码
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <stdio.h>
#include <vector>
#include <string>
#include <queue>
using namespace std;
struct node
{
vector<int> edge;
int in;
};
node n[501];
int N, M;
priority_queue<int,vector<int>,greater<int> > q;
int isVisited[501];
void topology()
{
for (int i = 1; i <= N; i++)
{
if (n[i].in == 0)
{
q.push(i);
isVisited[i] = 1;
}
}
int t=0;
while (q.size())
{
int index = q.top();
q.pop();
cout << index;
t++;
if(t<N)cout<<" ";
for (int j = 0; j < n[index].edge.size(); j++)
{
int s=n[index].edge[j];
n[s].in--;
}
for (int i = 1; i <= N; i++)
{
if (!isVisited[i] && n[i].in == 0)
{
isVisited[i] = 1;
q.push(i);
}
}
}
cout<<endl;
}
int main()
{
while (~scanf("%d %d", &N, &M))
{
while (q.size())
{
q.pop();
}
memset(isVisited,0,sizeof(isVisited));
for (int i = 0; i < 501; i++)
{
n[i].in = 0;
n[i].edge.clear();
}
int x, y;
for (int i = 0; i < M; i++)
{
scanf("%d %d", &x, &y);
n[x].edge.push_back(y);
n[y].in++;
}
topology();
}
}
3.总结
- 通过这道题目,学会优先队列的用法,了解到利bfs和dfs进行拓扑排序的区别
- 熟悉拓扑排序的写法。