確定比賽名次(hdu-1285)(拓撲排序佇列實現)
阿新 • • 發佈:2019-01-29
分析:
就是找出是否存在拓撲排序。
每次從該集合中取出(沒有特殊的取出規則,隨機取出也行,使用佇列/棧也行,下同)一個頂點,將該頂點放入儲存結果的List中。
緊接著迴圈遍歷由該頂點引出的所有邊,從圖中移除這條邊,同時獲取該邊的另外一個頂點,如果該頂點的入度在減去本條邊之後為0,那麼也將這個頂點放到入度為0的集合中。然後繼續從集合中取出一個頂點…………
當集合為空之後,檢查圖中是否還存在任何邊,如果存在的話,說明圖中至少存在一條環路。不存在的話則返回結果List,此List中的順序就是對圖進行拓撲排序的結果。
本質就是不斷找出入度為0的點,並儲存下來,可以用佇列儲存。
#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<stack>
#include<cstring>
using namespace std;
const int maxn=1000+5;
int indegree[maxn],graph[maxn][maxn];//indegree記錄入度,graph記錄關係
queue<int>ans; //用佇列儲存入度為0的點
int main()
{
int n,m;
while(cin>>n>>m)
{
if (n==0&&m==0)
break;
//初始化陣列
memset(indegree,0,sizeof(indegree));
memset(graph,0,sizeof(graph));
while(!ans.empty()) //清空ans
ans.pop();
for(int i=0;i<m;i++)
{
int a,b;
cin>>a>>b;
graph[a][b]=1 ;
}
//計算入度
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(graph[i][j]==1)
indegree[j]++;
//將入度為0的儲存進ans中
for(int i=0;i<n;i++)
if(indegree[i]==0)
ans.push(i);
int num=0; //記錄次數
while(!ans.empty())
{
int v1=ans.front(); //取佇列首元素
num++;
ans.pop(); //出隊
//找出以隊首元素為起點的邊,刪除首頂點和與之相連的邊,則末端入度減一
for(int i=0;i<n;i++)
{
if(graph[v1][i]==1)
{
indegree[i]--;
if(indegree[i]==0) //將入度為0的再放入ans中
ans.push(i);
}
}
}
// cout<<res.size()<<endl;
if(num==n)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
}