拓扑排序:由某个集合上的一个偏序得到该集合上的一个全序的操作。
拓扑排序操作过程:首先选择一个无前驱的顶点(即入度为0的顶点,图中至少应该有一个这样的顶点,否则肯定存在回路),然后从图中移去该顶点以及由其发出的所有有向边,如果图中还存在无前驱的顶点,则重复上述操作,直到操作无法进行。如果图不为空,说明图中存在回路,无法进行拓扑排序;否则移出的顶点的顺序就是对该图的一个拓扑排序。
例题1:hdu 1285题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285,简单的拓扑排序问题,代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=505;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int n,m,Indgree[MAX],map[MAX][MAX],top[MAX];
bool visited[MAX];
void Init()
{ CLR(map,0);
CLR(Indgree,0);
}
void TopSort()
{ int num=1;
CLR(visited,false);
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
if(!Indgree[j]&&!visited[j])//找出度数为0的点,且没有被访问
{ visited[j]=true;
top[num++]=j;
break;//这里一定要加break语句,可能题目中入度为0的点不只一个
}
for(int k=1;k<=n;k++)
if(map[top[num-1]][k])
{ map[top[num-1]][k]=0; //移除与该点相连的边
Indgree[k]--;
}
}
}
int main()
{ int u,v;
while(cin>>n>>m)
{ Init();
for(int i=1;i<=m;i++)
{ cin>>u>>v;
if(!map[u][v])
{ map[u][v]=1;
Indgree[v]++;
}
}
TopSort();
for(int i=1;i<=n;i++)
cout<<(i==1?"":" ")<<top[i];
cout<<endl;
}
return 0;
}
涉及到拓扑排序的题目有:HDU 3342,2647,POJ 1094,2367,3272,3687等等
其中HDU 3342是判断能不能进行拓扑排序,也就是说能不能形成环,只要在上面的例子中看num==n就输出"YES",否则输出"NO".
nyist 349,题目链接:NYOJ 349(Sorting It All Out),要分析的情况很多,不会做~~贴个代码,慢慢的看~~~
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=30;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int n,m,temp[MAX],Indgree[MAX],map[MAX][MAX],top[MAX];
void Init()
{ CLR(Indgree,0);
CLR(map,0);
}
int Topsort()
{ int num=0,flag=1,sum;
for(int i=0;i<n;i++)
temp[i]=Indgree[i];
for(int k=0;k<n;k++)
{ sum=0;
for(int j=0;j<n;j++)
{ if(!temp[j])
{ top[num++]=j;
sum++;
}
}
if(sum==0) return -1;
if(sum>1) flag=0;
temp[top[num-1]]--;
for(int j=0;j<n;j++)
if(map[top[num-1]][j]) temp[j]--;
}
if(flag) return 1;
return 0;
}
int main()
{ while(scanf("%d%d",&n,&m)&&n||m)
{ Init();
int flag=1;
for(int i=0;i<m;i++)
{ char s[3];
scanf("%s",s);
if(!map[s[0]-'A'][s[2]-'A'])
{ map[s[0]-'A'][s[2]-'A']=1;
Indgree[s[2]-'A']++;
}
if(flag)
{ if(Topsort()==1)
{ printf("Sorted sequence determined after %d relations: ",i+1);
for(int j=0;j<n;j++)
printf("%c",top[j]+'A');
printf(".\n");
flag=0;
}
if(Topsort()==-1)
{ printf("Inconsistency found after %d relations.\n",i+1);
flag=0;
}
}
}
if(flag) printf("Sorted sequence cannot be determined.\n");
}
return 0;
}
这个代码放在POJ的1094上会WA~有时候真的没有搞懂~~~超不爽!头都弄晕了~
~~~
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=1000;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int Indegree[MAX],map[MAX][MAX],top[MAX];
int n,m,visit[MAX];
void Init()
{ CLR(map,0);
CLR(Indegree,0);
}
int Topsort()
{ int num=0;
CLR(visit,0);
for(int i=1;i<=n;i++)
{ for(int j=1;j<=n;j++)
if(!Indegree[j]&&!visit[j])
{ visit[j]=1;
top[num++]=j; //找出入度为0的点
break;
}
for(int j=1;j<=n;j++)
if(map[top[num-1]][j])
{ map[top[num-1]][j]=0;
Indegree[j]--;
}
}
if(num==n) return 1;
return 0;
}
int main()
{ int u,v,Case;
scanf("%d",&Case);
while(Case--)
{ scanf("%d%d",&n,&m);
Init();
for(int i=0;i<m;i++)
{ scanf("%d%d",&u,&v); //要安装u必须先安装v,u为入度
map[v][u]=1;
Indegree[u]++;
}
if(Topsort())
{ for(int i=0;i<n-1;i++)
printf("%d ",top[i]);
printf("%d\n",top[n-1]);
}
else printf("-1\n");
}
system("pause");
return 0;
}