其实早就应该学习一下拓扑排序了,而且之前有几次也确实遇到了这类的问题,但是由于我的懒惰却一直没有真正的拿出时间去掌握它,或者看两眼没看懂也就算了。
之前也看过博客上的一些介绍,但是总感觉理论性太强,也太长了,没耐心看。其实真正学习图论的话这些基础的理论知识还是十分关键的。
学习图论的时候总是有这样的感觉,就是觉得虽然代码可能会写,但是没有系统的学习理论知识,所以做起题来总是不太可靠,稳定性不够。其实我也根本没怎么学过图论的东西,以后应该系统学习。
但是作为入门,所以先不要求自己具备多么系统的理论基础了,先把算法和代码实现理解了再说吧。
其实最后让我真正看明白的还是《算法竞赛入门经典》这本书。这本书上介绍的是深度搜索的拓扑排序。和算法导论上介绍的算法一样。
深度优先搜索拓扑排序 算法思想:用DFS遍历整个图,得出个节点的完成时间,然后按完成时间倒序排列就得到了图的拓扑排序序列
int G[30][30];
int n,m;
int c[30];
int topo[30];
int t;
bool dfs(int u)
{
c[u]=-1;
for(int v=0; v<n; v++) if(G[u][v])
{
if(c[v]<0) return false;
else if(!c[v] && !dfs(v)) return false;
}
c[u]=1;
topo[--t]=u+1;
return true;
}
bool toposort()
{
t=n;
memset(c,0,sizeof(c));
for(int u=n-1; u>=0; u--) if(!c[u])
{
if(!dfs(u)) return false;
}
return true;
}
还有一种是广度优先搜索求拓扑排序的。
基本思想:(1)从有向图中选择一个没有前驱(即入度为0)的顶点并且输出它.(2)从网中删去该顶点,并且删去从该顶点发出的全部有向边.(3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止.
int topo[1001];
int G[1005][1005];
int indegree[1005];
int n,m;
bool toposort() /// G[0,n)
{
int cnt=0,i,j,k;
for(i=0;i<n;i++) // 执行n次删点操作
{
for(j=0;j<n;j++) // 循环找入度为0的点
{
if(indegree[j]==0)
{
indegree[j]--; // 删除该点
topo[cnt++]=j+1; // 记录拓扑序
for(k=0;k<n;k++) //删除与该点相连的边
if(G[j][k]) indegree[k]--;
break;
}
if(j==n-1) //如果没找到入度为0的点,即成环
{
return false;
}
}
}
return true;
}