拓扑排序:由某个集合上的一个偏序得到该集合上的一个全序的操作。
拓扑排序操作过程:首先选择一个无前驱的顶点(即入度为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;
}