【模板題】【圖】拓撲排序 兩道例題,兩種思路:貪心策略及DFS
阿新 • • 發佈:2019-01-09
題目大意:給出一堆關係類似"A<B",有三種結果:1)在第k個關係讀入後出現環路,2)在第k個關係讀入後能夠確定排序,3)無法確定順序。
注意:
1、出現結果1、2之後之後的s要讀但是操作略過
2、要判斷重複的邊(入度不能重複加)
3、要先判斷環路再判斷是否有多個入度為0的點(即沒有全部排序)
#include<iostream> #include<string.h> #include<string> #include<queue> using namespace std; int n,m,ans,opt; bool g[27][27]; int gin[27]; char sortout[27]; int top; bool topo(int c) { queue<int> Q; int i,u,tin[27]; bool unsure=false; for (i=1;i<=n;i++) if (gin[i]==0) Q.push(i); top=0; memcpy(tin,gin,sizeof(gin)); while(!Q.empty()) { if (Q.size()>1) unsure=true;//多個入度為1,肯定沒有全部排序 u=Q.front();Q.pop(); sortout[top++]=u+'A'-1; for (i=1;i<=n;i++) if (g[u][i]) { tin[i]--; if (tin[i]==0) Q.push(i); } } //注意先判斷環路,才判斷無結果! if (top<n)//節點沒有輸出完就已經沒有入度為0的點則有環 { opt=2;ans=c;return 1; } else if (unsure) return 0; else//top==n { opt=1;ans=c;return 1; } return 0; } void solve() { int i,a,b; string s; bool flag=false; memset(g,0,sizeof(g)); memset(gin,0,sizeof(gin)); for (i=1;i<=m;i++) { cin>>s; if (flag) continue; a=s[0]-'A'+1;b=s[2]-'A'+1; if (g[b][a])//有環 { opt=2;ans=i; flag=true;continue; } if (!g[a][b])//判斷之前是否插入過該條邊 { g[a][b]=true; gin[b]++; } flag=topo(i); } if (!flag) opt=3; } int main() { int i; while(cin>>n>>m) { if (n==0&&m==0) break; solve(); if (opt==1) { cout<<"Sorted sequence determined after "<<ans<<" relations: "; for (i=0;i<top;i++) cout<<sortout[i]; cout<<"."<<endl; } else if (opt==2) cout<<"Inconsistency found after "<<ans<<" relations."<<endl; else cout<<"Sorted sequence cannot be determined."<<endl; } return 0; }
題目大意:給任務排序,並輸出順序。
ps:還是使用貪心比較好,DFS比較耗時
貪心解法:
#include<iostream> #include<string.h> #include<queue> using namespace std; int n,m; bool g[101][101]; int gin[101]; int c[101]; int top; void topo() { int i; int u; top=0; queue<int> Q; for (i=1;i<=n;i++) if (gin[i]==0) Q.push(i); while(!Q.empty()) { u=Q.front();Q.pop(); c[top++]=u; for (i=1;i<=n;i++) { if (g[u][i]) { gin[i]--; if (gin[i]==0) Q.push(i); } } } } int main() { int i,a,b; while(cin>>n>>m) { if (n==0&&m==0) break; memset(g,0,sizeof(g)); memset(gin,0,sizeof(0)); for (i=0;i<m;i++) { cin>>a>>b; g[a][b]=1; gin[b]++; } topo(); for (i=0;i<top-1;i++) cout<<c[i]<<" "; cout<<c[i]<<endl; } return 0; }
DFS解法:
//AC #include<iostream> #include<vector> #include<string.h> using namespace std; bool g[105][105]={0}; int n,m; int c[200]; int topo[200], t; bool dfs(int u) { c[u] = -1; //訪問標誌 for(int v = 1; v <= n; v++) if(g[u][v]) { if(c[v]<0) return false; //存在有向環,失敗退出 else if(!c[v] && !dfs(v)) return false; } c[u] = 1; topo[--t]=u; return true; } bool toposort( ) { t = n; memset(c, 0, sizeof(c)); for(int u = 1; u <= n; u++) if(!c[u]) if(!dfs(u)) return false; return true; } int main() { int i,j,x,y,count,point; while(cin>>n>>m) { if (n==0 && m==0) break; memset(g,0,sizeof(g)); for (i=1;i<=m;i++) { cin>>x;cin>>y; g[x][y]=1; } toposort(); for (i=0;i<n-1;i++) cout<<topo[i]<<" "; cout<<topo[i]<<endl; } return 0; }