zoukankan      html  css  js  c++  java
  • 拓扑排序

    定义

    拓扑排序是图G的所有节点的一种线性次序,该次序满足下列条件:如果图G包含边(u,v),
    则节点u在拓扑排序中处于节点v的前面(如果图G中包含环路,则不可能排出一个线性次序)。
    也可以说,u,v之间存在一条可达路径,则u的拓扑序在v的前面。
    

    算法实现

    DFS

    发现时间 d:该节点第一次被发现。
    完成时间 f:该节点所有的可达节点都被发现。
    使用DFS对有向无环图进行深度优先搜索,如果u.f < v.f,则在拓扑排序中u在v之前。
    严谨的证明可以参考算法导论,不严谨的证明如下:如果v.f > u.f 则可以证明,图中存在一条v->u的可达路径,因为只有将v节点的所有可达节点都完成后,才会标记v的完成时间,
    该时间一定比u的标记时间晚,也即是v.f  > u.f;参考上面关于拓扑排序 的定义,(完成时间)--> (u,v 之间存在路径)-->(u,v之间的拓扑序)可以知道,通过完成时间,我们可以确定
    拓扑顺序,即完成时间越晚,拓扑序越靠前。
    

    实现

    代码中,当一个点的所有节点被发现,也即是该节点已完成,则根据完成时间与拓扑序关系,将其放入拓扑排序的数组里。
    使用vector建立邻接表。
    
    vector<int> nod[101];
    int n;
    int vis[101];//存放访问的时间
    int order[101];//存放拓扑排序的顺序
    int t = 0;
    int num;
    void dfs(int s)
    {
    	stack<int> st;
    	st.push(s);
    	vis[s] = ++t; 
    	while(!st.empty())
    	{
    		int now = st.top();
    		int len = nod[now].size();
    		int id;
    		bool has = false;
    		for(int i = 0; i < len; ++i)
    		{
    			id = nod[now][i];
    			if(vis[id] == 0)
    			{
    				st.push(id);
    				vis[id] = ++t;
    				has = true;
    				break;
    			}
    		}
    		if(!has)
    		{
    			st.pop();
    			order[num--] = now;
    		}
    		
    	}
     
    } 
    

    kahn算法

    集合S保存所有入度为零的点
    1.如果集合S为空,算法结束,否则:从所有节点中选出入度为零的点加入集合S.(可根据需要对集合S进行排序)
    2.从集合S中取出入度为零的点u,放入已确定拓扑序的节点序列末尾。遍历点u 的所有相邻边,对可达节点入度减一。如果可达节点入度为零,则加入集合S.
    3.回到1.
    算法结束后,如果此时检测所有点的的入度,存在入度不为零的点,则说明图中存在环路。
    
    可以理解为,如果入度为零,根据拓扑排序的定义。则不存在拓扑序更靠前的点,则该节点的拓扑序可以确定。
    

    实现

    使用vector存放邻接表。
    
    vector<int> nod[27];
    int n,m;
    int order[27];
    int in[27];
    int t = 0;
    int num;
    int topoSort(){
    	int ret = 1;
    	memset(vis,0,sizeof(vis));
    	memset(order,0,sizeof(order));
    	num = 0;
    	queue<int> q;
    	for(int i = 1; i <= n; ++i){
    		if(in[i] == 0)
    		{
    			q.push(i);
    		}
    	}
    	while(!q.empty()){
    		int now =  q.front();
    		q.pop();
    		int len = nod[now].size();
    		for(int i = 0; i < len; ++i)
    		{
    			--in[nod[now][i]];
    			if(in[nod[now][i]] == 0)
    			{
    				q.push(nod[now][i]);
    			}
    		}
    		order[++num] = now;
    	}
    	for(int i = 1; i <= n; ++i)//存在入度不为零的点,存在环路,则拓扑排序不存在 。
    	{
    		if(in[i] != 0)
    		{
    			ret = -1;
    		}
    	}
    	return ret;
    }
    

    例题
    POJ2367 Genealogical tree
    POJ1094 Sorting It All Out

  • 相关阅读:
    软件测试工具
    Linux笔记
    Google Test
    字典dict()
    元组tuple 可迭代对象
    列表list
    一些总结
    format()
    列表list
    format() expandtabs() 输入表格数据
  • 原文地址:https://www.cnblogs.com/lif323/p/9384381.html
Copyright © 2011-2022 走看看