專題訓練之拓步排序

推薦幾個博客:https://blog.csdn.net/dm_vincent/article/details/7714519 拓撲排序的原理及其實現php

https://blog.csdn.net/u012860063/article/details/38017661 拓撲排序的幾種寫法
node

https://blog.csdn.net/shahdza/article/details/7779389 拓撲排序題集c++

 

1.基於DFS的拓撲排序:通常適用於數據較小而且須要判斷有無環的狀況算法

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=150;  6 int n,vis[maxn],topo[maxn],cnt;  7 bool g[maxn][maxn],flag;  8 
 9 void dfs(int u) 10 { 11     if ( vis[u]<0 ) { 12         flag=false; 13         return; 14  } 15     if ( vis[u]>0 ) return; 16     else vis[u]=-1; //表示當前還在訪問中 
17     for ( int v=1;flag&&v<=n;v++ ) { 18         if ( g[u][v] ) dfs(v); 19  } 20     topo[cnt--]=u; //保存下來 
21     vis[u]=1; //訪問完成 
22 } 23 
24 void toposort() 25 { 26     int i,j,k; 27     flag=true; 28     memset(vis,0,sizeof(vis)); //vis爲0表示初從未訪問過,爲1表示已經已經訪問完成,爲-1表示當前還在訪問中 
29     cnt=n; 30     for ( int i=1;i<=n&&flag;i++ ) { 31         if ( vis[i]==0 ) dfs(i); 32  } 33 } 34 
35 int main() 36 { 37     int i,m,x,y; 38     while ( scanf("%d%d",&n,&m)!=EOF ) { 39         memset(g,false,sizeof(g)); 40         while ( m-- ) { 41             scanf("%d%d",&x,&y); 42             g[x][y]=true; //g存儲兩個點的關係 
43  } 44  toposort(); 45         for ( int i=1;i<n;i++ ) printf("%d",topo[i]); 46         printf("%d\n",topo[n]); 47  } 48     return 0; 49 }
基於DFS的toposort

模板題(HDOJ3342)http://acm.hdu.edu.cn/showproblem.php?pid=3342數組

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=110;  6 int vis[maxn],topo[maxn],n,cnt;  7 bool g[maxn][maxn],flag;  8 
 9 void dfs(int u) 10 { 11     if ( vis[u]<0 ) { 12         flag=false; 13         return; 14  } 15     if ( vis[u]>0 ) return; 16     else vis[u]=-1; 17     for ( int v=1;v<=n&&flag;v++ ) { 18         if ( g[u][v] ) dfs(v); 19  } 20     topo[cnt--]=u; 21     vis[u]=1; 22 } 23 
24 void toposort() 25 { 26     memset(vis,0,sizeof(vis)); 27     flag=true; 28     cnt=n; 29     for ( int i=1;i<=n;i++ ) { 30         if ( vis[i]==0 ) dfs(i); 31  } 32 } 33 
34 int main() 35 { 36     int m,i,j,k,x,y; 37     while ( scanf("%d%d",&n,&m)!=EOF && n ) { 38         memset(g,false,sizeof(g)); 39         for ( i=1;i<=m;i++ ) { 40             scanf("%d%d",&x,&y); 41             x++;y++; 42             g[x][y]=true; 43  } 44  toposort(); 45         if ( flag ) printf("YES\n"); 46         else printf("NO\n"); 47  } 48     return 0; 49 }
HDOJ3342

 

2.kahn算法求拓撲排序ide

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 priority_queue<int,vector<int>,greater<int> >que;  8 const int maxn=505;  9 vector<int>G[maxn]; 10 int ans[maxn],ind[maxn],n; 11 
12 void toposort() 13 { 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=0; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[++cnt]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     for ( int i=1;i<=n;i++ ) { 29         printf("%d",ans[i]); 30         if ( i==n ) printf("\n"); 31         else printf(" "); 32  } 33 } 34 
35 int main() 36 { 37     int m,i,j,k,x,y; 38     while ( scanf("%d%d",&n,&m)!=EOF ) { 39         for ( i=1;i<=n;i++ ) G[i].clear(); 40         memset(ind,0,sizeof(ind)); 41         while ( m-- ) { 42             scanf("%d%d",&x,&y); 43  G[x].push_back(y); 44             ind[y]++; 45  } 46  toposort(); 47  } 48     return 0; 49 }
Kahn

 

作法:spa

首先統計每一個結點的入度。將度爲0的結點編號放入隊列 / 優先隊列中。
而後進行循環:
  1. 取出隊頭結點,存入ans數組。
  2. 而後「刪除與該點相連的邊」,即將從這個點出發到其餘點的邊所在的終點的入度-1;
  3. 若是-1之後,終點的入度變爲了0,那麼將終點的編號入隊列。
  4. 不斷循環直到隊列爲空/ans數組保存了n個元素

模板題(HDOJ1285)http://acm.hdu.edu.cn/showproblem.php?pid=1285.net

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 priority_queue<int,vector<int>,greater<int> >que;  8 const int maxn=505;  9 vector<int>G[maxn]; 10 int ans[maxn],ind[maxn],n; 11 
12 void toposort() 13 { 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=1; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[cnt++]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     for ( int i=1;i<=n;i++ ) { 29         printf("%d",ans[i]); 30         if ( i==n ) printf("\n"); 31         else printf(" "); 32  } 33 } 34 
35 int main() 36 { 37     int m,i,j,k,x,y; 38     while ( scanf("%d%d",&n,&m)!=EOF ) { 39         for ( i=1;i<=n;i++ ) G[i].clear(); 40         memset(ind,0,sizeof(ind)); 41         while ( m-- ) { 42             scanf("%d%d",&x,&y); 43  G[x].push_back(y); 44             ind[y]++; 45  } 46  toposort(); 47  } 48     return 0; 49 }
HDOJ1285

 

總結:拓撲序列是由某個集合上的一個偏序獲得該集合上的一個全序。題目每每給定一個偏序。而全序每每是按照必定的要求才能獲得的(這樣的要求每每體如今優先隊列中須要維護的變量上)。通常是要求字典序最小,有時候也會有不少附加條件,都是爲了獲得這個全序。code

練習題:對象

1.(HDOJ4857)http://acm.hdu.edu.cn/showproblem.php?pid=4857

分析:該題字典序最小不一樣,該題的目的是不斷想辦法使當前全部未訪問過的節點中編號最小的先出來。即存在6-4-1和3-9-2,由於當前存在的編號最小的是1,全部先讓6 4 1先出來,6 4出來的目的是使1儘早出來。所以該題只須要反向建圖,每次取出編號大的保存在ans數組的尾端。最關鍵的一點是小的頭部不必定排在前面,而大的尾部必定排在後面

推薦一個解釋較好的博客:https://blog.csdn.net/u012861385/article/details/38059515

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=30010;  8 vector<int>G[maxn];  9 int ans[maxn],ind[maxn],n; 10 
11 void toposort() 12 { 13     priority_queue<int>que; 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=n; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[cnt--]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     for ( int i=1;i<=n;i++ ) { 29         printf("%d",ans[i]); 30         if ( i==n ) printf("\n"); 31         else printf(" "); 32  } 33 } 34 
35 int main() 36 { 37     int m,i,j,k,x,y,T; 38     scanf("%d",&T); 39     while ( T-- ) { 40         scanf("%d%d",&n,&m); 41         for ( i=1;i<=n;i++ ) G[i].clear(); 42         memset(ind,0,sizeof(ind)); 43         while ( m-- ) { 44             scanf("%d%d",&x,&y); 45  G[y].push_back(x); 46             ind[x]++; 47  } 48  toposort(); 49  } 50     return 0; 51 }
HDOJ4857

 

2.(HDOJ2647)http://acm.hdu.edu.cn/showproblem.php?pid=2647

題意:有n我的,m條要求,每條要求的內容爲(x,y),即x要求本身的獎金比y高,求老闆最少須要發多少獎金,每人至少888,當有矛盾時輸出-1

分析:當最後ans數組中保存的數cnt少於n時說明出現了環,此時矛盾輸出-1。能夠設置一個rk數組表示每一個人的「等級」,最後第i我的得到的獎金爲888+rk[i]。rk數組初始化爲-1,剛開始入度爲0的點rk爲0,對於邊(u,v)上的v點來講,rk[v]=max(rk[v],rk[u]+1)。而對於整個圖來講須要反向建圖。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=1e4+10;  8 typedef long long ll;  9 vector<int>G[maxn]; 10 int ans[maxn],ind[maxn],n,rk[maxn]; 11 
12 void toposort() 13 { 14     queue<int>que; 15     while ( !que.empty() ) que.pop(); 16     for ( int i=1;i<=n;i++ ) { 17         if ( ind[i]==0 ) { 18  que.push(i); 19             rk[i]=0; 20  } 21  } 22     int cnt=0; 23     while ( !que.empty() ) { 24         int tmp=que.front(); 25  que.pop(); 26         ans[++cnt]=tmp; 27         for ( int i=0;i<G[tmp].size();i++ ) { 28             int v=G[tmp][i]; 29             ind[v]--; 30             rk[v]=max(rk[v],rk[tmp]+1); 31             if ( ind[v]==0 ) que.push(v); 32  } 33  } 34     if ( cnt<n ) printf("-1\n"); 35     else { 36         ll sum=0; 37         for ( int i=1;i<=n;i++ ) sum+=rk[i]; 38         sum=(ll)888*n+sum; 39         printf("%lld\n",sum); 40  } 41 } 42 
43 int main() 44 { 45     int m,i,j,k,x,y; 46     while ( scanf("%d%d",&n,&m)!=EOF ) { 47         for ( i=1;i<=n;i++ ) G[i].clear(); 48         memset(ind,0,sizeof(ind)); 49         memset(rk,-1,sizeof(rk)); 50         while ( m-- ) { 51             scanf("%d%d",&x,&y); 52  G[y].push_back(x); 53             ind[x]++; 54  } 55  toposort(); 56  } 57     return 0; 58 }
HDOJ2647

 

3.(POJ3687)http://poj.org/problem?id=3687

題意:有n個球,每一個球的重量爲i(從1到n),如今要給每一個球貼標籤(編號),沒有兩個編號是同樣的;有m個要求,要求(x,y)表示第x個球的標籤要小於第y個球。

分析:大體同HDOJ4857,須要反向建圖,由於該題也是須要當前重量最小的球儘可能靠前

注意:輸出一行。第i個表示的是第i個球的編號,而不是拓步排序中的順序

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=205;  8 vector<int>G[maxn];  9 int ans[maxn],ind[maxn],n,pos[maxn]; 10 
11 void toposort() 12 { 13     priority_queue<int>que; 14     while ( !que.empty() ) que.pop(); 15     for ( int i=1;i<=n;i++ ) { 16         if ( ind[i]==0 ) que.push(i); 17  } 18     int cnt=n; 19     while ( !que.empty() ) { 20         int tmp=que.top(); 21  que.pop(); 22         ans[cnt--]=tmp; 23         for ( int i=0;i<G[tmp].size();i++ ) { 24             ind[G[tmp][i]]--; 25             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 26  } 27  } 28     if ( cnt>0 ) { 29         printf("-1\n"); 30         return; 31  } 32     for ( int i=1;i<=n;i++ ) { 33         pos[ans[i]]=i; 34  } 35     for ( int i=1;i<=n;i++ ) { 36         printf("%d",pos[i]); 37         if ( i==n ) printf("\n"); 38         else printf(" "); 39  } 40 } 41 
42 int main() 43 { 44     int m,i,j,k,x,y,T; 45     scanf("%d",&T); 46     while ( T-- ) { 47         scanf("%d%d",&n,&m); 48         for ( i=1;i<=n;i++ ) G[i].clear(); 49         memset(ind,0,sizeof(ind)); 50         while ( m-- ) { 51             scanf("%d%d",&x,&y); 52  G[y].push_back(x); 53             ind[x]++; 54  } 55  toposort(); 56  } 57     return 0; 58 }
POJ3687

 

4.(POJ3553)http://poj.org/problem?id=3553

題意:有n項工做,每項工做有一個持續時間和截至時間。有m條關係,每條關係(x,y)表示任務x必定要在任務y前進行。對於任務j來講當前的完成時間記作cj,現使得全部任務的max[cj-dj,0]最小,求任務進行的順序

分析:由偏序獲得全序的條件是max[cj-dj,0]最小,那麼咱們能夠將優先隊列中的順序按照d從小到大進行排列。假設當前的時間爲now,當前最小的d對應的任務爲i,持續時間爲pi,截至時間爲di,此時有差值value1=abs(now+pi-di)。若此時不進行任務i,而進行其餘任務j,下次再進行任務i對於任務i來講value2=abs(now+pj+pi-di)必定是比value1要更大的。全部對於當前的局面來講每次取di最小的能夠獲得最優的答案

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 #include<cmath>
 7 using namespace std;  8 const int maxn=50010;  9 struct node{ 10     int p; 11     int d; 12     int id; 13     node(int _p=0,int _d=0,int _id=0):p(_p),d(_d),id(_id) {} 14     bool operator < (const node &r)const
15  { 16         return d>r.d; 17  } 18 }arr[maxn]; 19 vector<int>G[maxn]; 20 int ans[maxn],ind[maxn],n; 21 
22 void toposort() 23 { 24     int num,now; 25     num=now=0; 26     priority_queue<node>que; 27     while ( !que.empty() ) que.pop(); 28     for ( int i=1;i<=n;i++ ) { 29         if ( ind[i]==0 ) que.push(node(arr[i].p,arr[i].d,arr[i].id)); 30  } 31     int cnt=0; 32     while ( !que.empty() ) { 33         node tmp=que.top(); 34  que.pop(); 35         int u=tmp.id; 36         now+=arr[u].p; 37         num=max(num,abs(now-arr[u].p)); 38         ans[++cnt]=u; 39         for ( int i=0;i<G[u].size();i++ ) { 40             int v=G[u][i]; 41             ind[v]--; 42             if ( ind[v]==0 ) que.push(node(arr[v].p,arr[v].d,v)); 43  } 44  } 45     for ( int i=1;i<=n;i++ ) { 46         printf("%d\n",ans[i]); 47  } 48 } 49 
50 int main() 51 { 52     int m,i,j,k,x,y; 53     while ( scanf("%d",&n)!=EOF ) { 54         for ( i=1;i<=n;i++ ) G[i].clear(); 55         memset(ind,0,sizeof(ind)); 56         for ( i=1;i<=n;i++ ) { 57             scanf("%d%d",&arr[i].p,&arr[i].d); 58             arr[i].id=i; 59  } 60         scanf("%d",&m); 61         while ( m-- ) { 62             scanf("%d%d",&x,&y); 63  G[x].push_back(y); 64             ind[y]++; 65  } 66  toposort(); 67  } 68     return 0; 69 }
POJ3553

 

5.(POJ2762)http://poj.org/problem?id=2762

題意:給定的圖中是否知足對於任意兩點(u,v),總有u到v或者v到u

分析:強連通份量。先縮點,而後判斷出入度爲1的點是否都只有一個.由於當且僅當圖爲一條鏈時才知足條件,若是出現分叉則必定不知足條件。

作法2:先縮點再進行toposort,當每次彈出隊列中最前面的元素時進行判斷隊列中是否還有其餘元素,若是有則不成立。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;  7 const int maxn=1050;  8 const int maxm=15000;  9 struct edge{  10     int to,nxt;  11 }edge[maxm];  12 int head[maxn],tot;  13 int low[maxn],dfn[maxn],stack[maxn],belong[maxn];  14 int index,top;  15 int scc;  16 bool vis[maxn];  17 int num[maxn];  18 vector<int>G[maxn];  19 int ans[maxn],ind[maxn],n,out[maxn];  20 
 21 void addedge(int u,int v)  22 {  23     edge[tot].to=v;  24     edge[tot].nxt=head[u];  25     head[u]=tot++;  26 }  27 
 28 void tarjan(int u)  29 {  30     int v;  31     low[u]=dfn[u]=++index;  32     stack[top++]=u;  33     vis[u]=true;  34     for ( int i=head[u];i!=-1;i=edge[i].nxt ) {  35         v=edge[i].to;  36         if ( !dfn[v] ) {  37  tarjan(v);  38             low[u]=min(low[u],low[v]);  39  }  40         else if ( vis[v] ) low[u]=min(low[u],dfn[v]);  41  }  42     if ( low[u]==dfn[u] ) {  43         scc++;  44         do {  45             v=stack[--top];  46             vis[v]=false;  47             belong[v]=scc;  48             num[scc]++;  49  }  50         while ( v!=u );  51  }  52 }  53 
 54 void solve(int N)  55 {  56     memset(dfn,0,sizeof(dfn));  57     memset(vis,false,sizeof(vis));  58     memset(num,0,sizeof(num));  59     index=scc=top=0;  60     for ( int i=1;i<=N;i++ ) {  61         if ( !dfn[i] ) tarjan(i);  62  }  63 }  64 
 65 void init()  66 {  67     tot=0;  68     memset(head,-1,sizeof(head));  69 }  70 
 71 int main()  72 {  73     int m,i,j,k,x,y,z,T;  74     scanf("%d",&T);  75     while ( T-- ) {  76         scanf("%d%d",&n,&m);  77  init();  78         for ( i=0;i<m;i++ ) {  79             scanf("%d%d",&x,&y);  80  addedge(x,y);  81  }  82  solve(n);  83         for ( i=1;i<=scc;i++ ) G[i].clear();  84         memset(ind,0,sizeof(ind));  85         memset(out,0,sizeof(out));  86         for ( i=1;i<=n;i++ ) {  87             for ( j=head[i];j!=-1;j=edge[j].nxt ) {  88                 int v=edge[j].to;  89                 if ( belong[i]!=belong[v] ) {  90                     ind[belong[v]]++;  91                     out[belong[i]]++;  92  }  93  }  94  }  95         int now1,now2;  96         now1=now2=0;  97         for ( i=1;i<=scc;i++ ) {  98             if ( ind[i]==0 ) now1++;  99             if ( out[i]==0 ) now2++; 100  } 101         if ( now1==1 && now2==1 ) printf("Yes\n"); 102         else printf("No\n"); 103  } 104     return 0; 105 }
POJ2762

 

6.(HDOJ1811)http://acm.hdu.edu.cn/showproblem.php?pid=1811

分析:並查集+toposort。首先並查集的做用在於對於那些rating相等的人他們之間的排名必定是肯定的,這時候能夠考慮「縮點」,將那些rating相等的人縮成一個點,此時要注意不能邊縮點邊建圖,而是須要先所有縮點完成後再建圖,不然建圖會有誤。同時在整個toposort的過程當中,對象的編號是並查集完成後的編號,對象的數目是縮點後的數目。對於三種狀況的斷定:當出現環時則爲矛盾(此時cnt<num)。判斷信息是否完備的條件同POJ2762,當只有一條鏈時才能說明信息完備,此時判斷每一個點彈出隊列後是否還有元素在隊列當中。其餘狀況輸出OK。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<queue>
 5 #include<vector>
 6 using namespace std;  7 const int maxn=100005;  8 vector<int>G[maxn];  9 int n,ind[maxn],cnt,F[maxn],sum; 10 struct node{ 11     int a; 12     int b; 13     char c; 14 }arr[maxn*2]; 15 
16 int find(int x) 17 { 18     if ( F[x]==-1 ) return x; 19     return F[x]=find(F[x]); 20 } 21 
22 void merge(int x,int y) 23 { 24     int dx,dy; 25     dx=find(x); 26     dy=find(y); 27     if ( dx!=dy ) F[dx]=dy; 28 } 29 
30 void toposort() 31 { 32     queue<int>que; 33     bool flag=false; 34     cnt=0; 35     for ( int i=0;i<n;i++ ) { 36         if ( ind[i]==0 && F[i]==-1 ) que.push(i); //F[i]==-1的判斷條件不能遺漏 
37  } 38     while ( !que.empty() ) { 39         
40         int tmp=que.front(); 41  que.pop(); 42         if ( !que.empty() ) flag=true; //判斷是否爲直鏈 
43         cnt++; 44         for ( int i=0;i<G[tmp].size();i++ ) { 45             ind[G[tmp][i]]--; 46             if ( ind[G[tmp][i]]==0 ) que.push(G[tmp][i]); 47  } 48  } 49     if ( cnt<sum ) printf("CONFLICT\n"); 50     else if ( flag ) printf("UNCERTAIN\n"); 51     else printf("OK\n"); 52 } 53 
54 int main() 55 { 56     int m,i,j,k,fy,fx; 57     char s; 58     while ( scanf("%d%d",&n,&m)!=EOF ) { 59         memset(ind,0,sizeof(ind)); 60         memset(F,-1,sizeof(F)); 61         for ( i=0;i<n;i++ ) G[i].clear(); 62         for ( i=1;i<=m;i++) { 63             scanf("%d %c %d",&arr[i].a,&arr[i].c,&arr[i].b); 64             if ( arr[i].c=='=' ) merge(arr[i].a,arr[i].b); 65  } 66         for ( i=1;i<=m;i++ ) { 67             fx=find(arr[i].a); 68             fy=find(arr[i].b); 69             if ( arr[i].c=='=' ) continue; 70             else if ( arr[i].c=='>' ) { 71  G[fx].push_back(fy); 72                 ind[fy]++; 73  } 74             else if ( arr[i].c=='<' ) { 75  G[fy].push_back(fx); 76                 ind[fx]++; 77  } 78  } 79         sum=0; 80         for ( i=0;i<n;i++ ) { 81             if ( F[i]==-1 ) sum++; 82  } 83  toposort(); 84  } 85     return 0; 86 }
HDOJ1811

 

7.(HDOJ3357)http://acm.hdu.edu.cn/showproblem.php?pid=3357

題意:有n個公司和m筆交易,每筆交易(x,y)表示x公司買y公式的股份,當一個公司試圖購買其父公司的股份時交易便會被中止,求中止的交易數

分析:原本應該每次加一條邊而後進行一次拓撲排序判斷有無環,可是複雜度太大。因此才用floyd來判環。具體作法是每一個輸入(x,y),先判斷y是否爲x的父公司(即y購買過x的股份),同時須要判斷x是否等於y(容易遺漏)。若不是則經過floyd更新一次,可是每次floyd不能進行三層循環。對於添加的邊(x-y)來講能夠更新(i-x-y),(x-y-j),(i-x-y-j)三種邊,這時候能夠用floyd兩層循環搞定(最外層k只能爲x/y)。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=250;  6 bool d[maxn][maxn];  7 int n;  8 
 9 void floyd(int x,int y) 10 { 11     int i,j,k; 12     for ( i=1;i<=n;i++ ) { 13         if ( !d[i][x] ) continue; 14         for ( j=1;j<=n;j++ ) { 15             if ( d[i][j] || !d[x][j] ) continue; 16             d[i][j]=true; 17  } 18  } 19     for ( i=1;i<=n;i++ ) { 20         if ( !d[i][y] ) continue; 21         for ( j=1;j<=n;j++ ) { 22             if ( d[i][j] || !d[y][j] ) continue; 23             d[i][j]=true; 24  } 25  } 26 } 27 
28 int main() 29 { 30     int i,j,k,x,y,z,m,h=0,ans; 31     while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) { 32         memset(d,false,sizeof(d)); 33         ans=0; 34         for ( i=1;i<=m;i++ ) { 35             scanf("%d%d",&x,&y); 36             if ( d[x][y] ) continue; 37             if ( d[y][x] || x==y ) { 38                 ans++; 39                 continue; 40  } 41             d[x][y]=true; 42  floyd(x,y); 43  } 44         printf("%d. %d\n",++h,ans); 45  } 46     return 0; 47 }
HDOJ3357(1)
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;  5 const int maxn=250;  6 bool d[maxn][maxn];  7 int n;  8 
 9 void floyd(int x,int y) 10 { 11     int i,j,k; 12     for ( i=1;i<=n;i++ ) { 13         if ( d[i][x] ) d[i][y]=true; 14         if ( d[y][i] ) d[x][i]=true; 15  } 16     for ( i=1;i<=n;i++ ) { 17         if ( !d[i][x] ) continue; 18         for ( j=1;j<=n;j++ ) { 19             if ( !d[y][j] || d[i][j] ) continue; 20             d[i][j]=true; 21  } 22  } 23 } 24 
25 int main() 26 { 27     int i,j,k,x,y,z,m,h=0,ans; 28     while ( scanf("%d%d",&n,&m)!=EOF && (n+m) ) { 29         memset(d,false,sizeof(d)); 30         ans=0; 31         for ( i=1;i<=m;i++ ) { 32             scanf("%d%d",&x,&y); 33             if ( d[y][x] || x==y ) { 34                 ans++; 35                 continue; 36  } 37             if ( d[x][y] ) continue; 38             d[x][y]=true; 39  floyd(x,y); 40  } 41         printf("%d. %d\n",++h,ans); 42  } 43     return 0; 44 }
HDOJ3357(2)
相關文章
相關標籤/搜索