拓扑排序是找DAG(有向无环图)的关键路径
拓扑排序从数据结构原理上说是不断找对应入度为0的点,找到就删去这个点和从此点出的边。这对应的其实是用bfs的方法,所以用bfs得到的其实除了判断还有每次找的出度为0的点(顺序不唯一),而dfs得到的是这个环的路径。(反正我一般都是并查集判断的。。)
先说bfs:
int in[N];
queue<int> qq;
void printfqq(){ // 输出拓扑序列,有环即无
while(qq.size()){
cout<<qq.front()<<" ";
qq.pop();
}
cout<<endl;
}
int ans = -1;
void bfs_topsort(){
queue<P> q;
int sum=0;
for(int i=1;i<=n;i++)
if(in[i]==0)
q.push(make_pair(i,1)),sum++;
while(!q.empty()){
P tmp = q.front();q.pop();
int now=tmp.first;
qq.push(now);
for(int i=head[now];~i;i=nex[i]){
int v = ver[i];
in[v]--;
if(in[v]==0){
q.push(make_pair(v,tmp.second+1));
ans = max(ans,tmp.second+1); // 最长链
sum++;
}
}
}
if(sum<n){
cout<<"有环:"<<endl;
}else cout<<"无环"<<endl;
printf("%d\n",ans);
printfqq();//这是拓扑排序后的序列,不是关键路径
}
dfs是对应遍历边,如果从当前点遍历到的点之前遍历过了,就有环,也就是找环路径:
int t,vis[N];
stack<int> st;
bool dfs(int x){
vis[x]=-1;//正在遍历中
for(int i=head[x];~i;i=nex[i]){
if(vis[ver[i]]==-1) return false;//存在环;
else if(!vis[ver[i]] && !dfs(ver[i])) {st.push(ver[i]);return false; }
}
vis[x]=1;//遍历结束
return true;
}
void dfs_topsort(){
t=n;
for(int i=1;i<=n;i++)
if(!vis[i] && !dfs(i)){
cout<<"有环:"<<endl;
return;
}
cout<<"无环";
}
下面贴测试代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 500;
int ver[N],nex[N];
int n,m,cnt;
int head[N],in[N],tp[N];
stack<int> st;
queue<int> qq;
void add(int a,int b){
ver[++cnt] = b;
nex[cnt] = head[a];
head[a] = cnt;
}
void init(){
memset(head,-1,sizeof head);
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b;scanf("%d %d",&a,&b);
add(a,b);
in[b]++;
}
}
void printfst(){
while(!st.empty()){
cout<<st.top()<<" ";
st.pop();
}
cout<<endl;
}
void printfqq(){
while(qq.size()){
cout<<qq.front()<<" ";
qq.pop();
}
cout<<endl;
}
void bfs_topsort(){
queue<int > q;
int sum=0;
for(int i=1;i<=n;i++)
if(in[i]==0)
q.push(i),sum++;
int cnt=0;
while(!q.empty()){
int now=q.front();q.pop();
tp[cnt++]=now;qq.push(now);
for(int i=head[now];~i;i=nex[i]){
in[ver[i]]--;
if(in[ver[i]]==0){
q.push(ver[i]);
sum++;
}
}
}
if(sum<n){
cout<<"有环:"<<endl;
}else cout<<"无环"<<endl;
printfqq();
}
int t,vis[N];
bool dfs(int x){
vis[x]=-1;//正在遍历中
for(int i=head[x];~i;i=nex[i]){
if(vis[ver[i]]==-1) return false;//存在环;
else if(!vis[ver[i]] && !dfs(ver[i])) {st.push(ver[i]);return false; }
}
vis[x]=1;//遍历结束
return true;
}
void dfs_topsort(){
t=n;
for(int i=1;i<=n;i++)
if(!vis[i] && !dfs(i)){
cout<<"有环:"<<endl;
return;
}
cout<<"无环";
}
int main(){
init();
bfs_topsort();//1 对应第一个测试样例
dfs_topsort();//2 3 4
printfst();
return 0;
}
/*两组测试数据:
1)有环
4 4
1 2
2 3
3 4
4 2
2)无环
12 16
1 2
1 3
2 3
1 4
3 5
4 5
11 6
5 7
3 7
3 8
6 8
9 10
9 11
9 12
10 12
1 12*/