概念:一个有向无环图的拓扑序列是将图中的顶点排成一个线性序列,使得对于图中任意一对顶点u,v。若存在边<u,v>,则线性序列中u出现在v之前。
算法实现:
(1)若图中的点入度均大于0则不存在拓扑序列,否则进行第二步
(2)取一个入度为0的点u并将其放置序列末尾
(3)删除点u以及从u伸出的边,即将与u相连的点的入度减1
(4)若图中还存在顶点,再从(1)开始
模板:
#include<cstdio> #include<vector> #include<cstring> #include<queue> #include<iostream> using namespace std; const int maxn=1e3; vector<int>grid[maxn]; int indu[maxn]; void find(int n){ queue<int>Q; for(int i=1;i<=n;i++)if(indu[i]==0)Q.push(i),cout<<i<<","; while(!Q.empty()){ int now=Q.front();Q.pop(); for(int i=0;i<grid[now].size();i++){ int next=grid[now][i]; if(--indu[next]==0)Q.push(next),cout<<next<<","; } } cout<<endl; } int main(){ int n,m; while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++)grid[i].clear(); memset(indu,0,sizeof(indu)); for(int i=0;i<m;i++){ int p1,p2; scanf("%d%d",&p1,&p2); grid[p1].push_back(p2);//p1到p2有一条边 indu[p2]++; } find(n); } return 0; }
题目:
基本应用之有向图判环:在while循环中加入计数,当循环结束时如果循环次数等于顶点个数,则证明n个顶点入度都已经为0 ,存在拓扑序列,则图中不存在环,反之有环,题目:HUD-3342
学会反向建图及按题意确定输出次序:HUD-1285
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<queue> #define MM(a) memset(a,0,sizeof(a)); using namespace std; const int maxn=510; vector<int>grid[maxn]; int indu[maxn]; void find(int N){ priority_queue<int,vector<int>,greater<int> >Q; for(int i=1;i<=N;i++)if(indu[i]==0)Q.push(i); vector<int>ans; while(!Q.empty()){ int now=Q.top();Q.pop(); //printf("-%d-\n",now); ans.push_back(now); for(int i=0;i<grid[now].size();i++){ int next=grid[now][i]; if(--indu[next]==0)Q.push(next); } } for(int i=0;i<ans.size();i++){ printf("%d",ans[i]); if(i==ans.size()-1)printf("\n"); else printf(" "); } } int main(){ int N,M; while(scanf("%d%d",&N,&M)==2 &&N){ for(int i=1;i<=N;i++)grid[i].clear(); MM(indu); for(int i=0;i<M;i++){ int p1,p2; scanf("%d%d",&p1,&p2); grid[p1].push_back(p2);//p2输给p1 indu[p2]++; } find(N); } return 0; }
福利题:poj-3687 Labeling Balls(别问我福利是啥,做了就知道了,嘿嘿)