1. 程式人生 > >HDU 1285 確定比賽名次(拓撲排序模板)

HDU 1285 確定比賽名次(拓撲排序模板)

href 正在 ios dfs als 結束 top 查找 names

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1285

題目大意:有N個比賽隊(1<=N<=500),編號依次為1,2,3,。。。。,N進行比賽,比賽結束後,裁判委員會要將所有參賽隊伍從前往後依次排名,但現在裁判委員會不能直接獲得每個隊的比賽成績,只知道每場比賽的結果,即P1贏P2,用P1,P2表示,排名時P1在P2之前。現在請你編程序確定排名。

解題思路:拓撲排序裸題,但是有要求並列的點序號小的排在前面。開始寫了一個dfs版倒序的怎麽寫都錯,後來發現根本做不了(可能是我太菜了)。。。。於是改寫了一個通過每次查找入讀為0的點,然後刪除有關邊的版本,一下就AC了。

先是對了的方法,先叫它減入度法吧,這種做法可以判斷有向圖是否成單鏈,也就是沒有分支,若一次找到入度為0的點有兩個則存在分支。

代碼:

 1 #include<iostream> 
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 using namespace std;
 6 const int N=5e2+5;
 7 
 8 int n,m;
 9 int degree[N];
10 bool G[N][N];
11 queue<int
>q; 12 13 void toposort(){ 14 for(int i=1;i<=n;i++){ 15 //尋找出度為0的點 16 int j=1; 17 while(degree[j]!=0) j++; 18 degree[j]--; 19 q.push(j); 20 //將關聯的點的入度減1,即刪除與該節點關聯的邊 21 for(int k=1;k<=n;k++){ 22 if(G[j][k]) 23 degree[k]--;
24 } 25 } 26 } 27 28 int main(){ 29 while(~scanf("%d%d",&n,&m)){ 30 memset(G,false,sizeof(G)); 31 memset(degree,0,sizeof(degree)); 32 for(int i=1;i<=m;i++){ 33 int a,b; 34 scanf("%d%d",&a,&b); 35 if(!G[a][b]){ 36 G[a][b]=true; 37 degree[b]++; 38 } 39 } 40 toposort(); 41 while(!q.empty()){ 42 if(q.size()==1) 43 printf("%d\n",q.front()); 44 else 45 printf("%d ",q.front()); 46 q.pop(); 47 } 48 } 49 return 0; 50 }

然後是dfs版的,雖然不能寫這題,但還是當個模板放著吧,dfs法可以在O(n^2)時間內判斷是否有環,而floyd需要O(n^3)。

代碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<stack>
 5 using namespace std;
 6 const int N=5e2+5;
 7 
 8 int n,m;
 9 int G[N][N],vis[N];//vis[i]=0,-1,1分別表示未訪問、正在訪問、已訪問並且已遞歸訪問完所有子孫
10 stack<int>res;
11 
12 
13 bool dfs(int u){
14     vis[u]=-1;
15     for(int i=1;i<=n;i++){
16         if(G[u][i]){
17             if(vis[i]<0) return false;
18             else if(!vis[i]&&!dfs(i))
19                 return false;
20         }
21     }
22     vis[u]=1;
23     res.push(u);
24     return true;
25 }
26 
27 bool toposort(){
28     memset(vis,0,sizeof(vis));
29     for(int i=1;i<=n;i++){
30         if(!vis[i]){
31             if(!dfs(i)) return false;
32         }
33     }
34     return true;
35 }
36 
37 int main(){
38     while(~scanf("%d%d",&n,&m)){
39         memset(G,0,sizeof(G));
40         for(int i=1;i<=m;i++){
41             int a,b;
42             scanf("%d%d",&a,&b);
43             G[a][b]=1;
44         }
45         toposort();
46         while(!res.empty()){
47             if(res.size()==1)
48                 printf("%d\n",res.top());
49             else
50                 printf("%d ",res.top());
51             res.pop();
52         }
53     }
54     return 0;
55 }

HDU 1285 確定比賽名次(拓撲排序模板)