这道题是拓扑排序的第一种应用:利用拓扑排序确定拓扑序列。
-
题目描述:
-
有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
//适用条件:题目给的这张图只能有一个(弱)连通分量(但不要求强连通)
#include <iostream>
#include <vector>
#include <queue>
#define MAXSIZE 600
using namespace std;
struct Edge{
int thisNode;
int nextNode;
Edge(){
}
Edge(int thisNode,int nextNode){
this->thisNode=thisNode;
this->nextNode=nextNode;
}
};
struct Vex{
};
struct Graph{
int graphSize;
vector<Edge> edge[MAXSIZE];
// vector<Vex> vex;
void initGraph(int graphSize){
this->graphSize=graphSize;
for (int i=0;i<graphSize;i++)
edge[i].clear();
// vex.clear();
}
void addEdge(int thisNode,int nextNode){
edge[thisNode].push_back(Edge(thisNode,nextNode));
}
};
int main(){
int n,m;
Graph graph;
int inDegree[MAXSIZE];
int cnt;
priority_queue<int,vector<int>,greater<int> > q;
queue<int> seq;
int thisNode,nextNode;
bool firstCase;
while (cin>>n>>m){
//initiate
graph.initGraph(n);
for (int i=0;i<graph.graphSize;i++)
inDegree[i]=0;
while (!q.empty())
q.pop();
while (!seq.empty())
seq.pop();
cnt=0;
//input & cal inDegree
for (int i=0;i<m;i++){
cin>>thisNode>>nextNode;
thisNode--;nextNode--;
graph.addEdge(thisNode,nextNode);
inDegree[nextNode]++;
}
//initiate q
for (int i=0;i<graph.graphSize;i++){
if (inDegree[i]==0)
q.push(i);
}
//Topological sorting
/*
使用队列q作为线索,利用了"新出现的入度为0的点必定是由边的删除造成的"这一特性,对顶点进行遍历,较之自己的算法逻辑更优
使用了cnt计数器与顶点总数n比较来判定是否顶点皆已删除,较之自己的算法逻辑更优
*/
while(!q.empty()){
int nowP=q.top();
seq.push(nowP);//record the seq
q.pop();//del the vex
cnt++;
for (int i=0;i<graph.edge[nowP].size();i++){//traverse the edges & reduce inDegree
int nextNode=graph.edge[nowP][i].nextNode;
inDegree[nextNode]--;
if (inDegree[nextNode]==0)
q.push(nextNode);
}
graph.edge[nowP].clear();//del the edges
}
//output
firstCase=true;
while (!seq.empty()){
if(firstCase==true)
firstCase=false;
else
cout<<' ';
cout<<seq.front()+1;
seq.pop();
}
cout<<endl;
}
return true;
}