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

    拓扑排序-维基百科

    用以下的简单算法得到一个DAG的拓扑排序,而且,所有的拓扑排序都可以通过这个算法得到。设需要进行拓扑排序的图为G,已经完成拓扑排序的顶点构成序列q

    1. 开始时,置图G1=Gq为空序列;
    2. 如果图G1是空图,则拓扑排序完成,算法结束,得到的序列q就是图G的一个拓扑排序;
    3. 在图G1中找到一个没有入边(即入度为0)的顶点v,将v放到序列q的最后(这样的顶点v必定存在,否则图G1必定有圈;因为图G有圈,故不是DAG);
    4. 从图G1中删去顶点v以及所有与顶点v相连的边e(通过将与v邻接的所有顶点的入度减1来实现),得到新的图G1,转到第二步。

    以上摘自维基百科

    以此题为例,用邻接表存储图

    有N个比赛队(1<=N<=500),编号依次为1,23,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。
    输入:输入有若干组,每组中的第一行为二个数N(
    1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。
    输出:给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。
    其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

    Sample input:
    4 3
    1 2
    2 3
    4 3
    Sample output:
    1 2 4 3
    #include <stdio.h>
    #include <malloc.h>
    
    #ifdef DEBUG
    #define MAX_NUM_TEAM -4
    #endif
    
    #ifndef DEBUG
    #define MAX_NUM_TEAM 500
    #endif
    
    /* 表结点 */
    typedef struct Node1
    {
    	int iNum;											/* 存储loser的序号 */
    	struct Node1 *next;									/* 存储winner对应的loser结点 */
    }EdgeNode;
    
    /* 头结点 */
    typedef struct Node2
    {
    	int iNumTeam, iNumRemain;							/* 分别表示总队数,未处理队 */
    	int iIndegree[MAX_NUM_TEAM+10];						/* 每个队对应顶点的入度 */
    	EdgeNode *sonNode[MAX_NUM_TEAM+10];					/* 子节点 */
    }TPGraphNode;
    
    typedef struct LIST
    {
    	int iNum;
    	int _array[MAX_NUM_TEAM+10];
    }List;
    
    int iNumMatch;
    TPGraphNode tpGraphNode;
    List list;												/* 用于存放拓扑排序后的序列 */
    
    /* 初始化 */
    void Init()
    {
    	int i;
    
    	tpGraphNode.iNumRemain = tpGraphNode.iNumTeam;
    	for (i = 1; i <= tpGraphNode.iNumTeam; i++)
    	{
    		tpGraphNode.iIndegree[i] = 0;
    		tpGraphNode.sonNode[i] = NULL;
    	}
    
    	list.iNum = 0;
    }
    
    void Input()
    {
    	int i, winner, loser;
    	EdgeNode *p;
    
    	for (i = 1; i <= iNumMatch; i++)
    	{
    		scanf("%d %d", &winner, &loser);
    		tpGraphNode.iIndegree[loser]++;					/* 入度+1 */
    		p = (EdgeNode *)malloc(sizeof(EdgeNode));		/* 申请新结点 */
    		p->iNum = loser;
    		if (NULL == tpGraphNode.sonNode[winner])		/* winner第一次赢得比赛 */
    		{
    			p->next = NULL;
    		}
    		else											/* 前插 */
    		{
    			p->next = tpGraphNode.sonNode[winner];
    		}
    		tpGraphNode.sonNode[winner] = p;
    	}
    }
    
    void TopologicalSort()
    {
    	int i;
    	EdgeNode *p, *q;
    
    	while (tpGraphNode.iNumRemain-- > 0)
    	{
    		for (i = 1; i <= tpGraphNode.iNumTeam; i++)		
    		{
    			if (0 == tpGraphNode.iIndegree[i])			/* 当找到入度为0的结点后,做以下处理,并跳出,从头开始查找 */
    			{
    				list._array[list.iNum++] = i;
    
    				p = tpGraphNode.sonNode[i];				/* 释放后继结点 */
    				while (NULL != p)
    				{
    					tpGraphNode.iIndegree[p->iNum]--;	/* 对应的序号的入度-1 */
    					q = p->next;	
    					free(p);
    					p = q;
    				}
    				tpGraphNode.iIndegree[i] = -1;			/* 标记已处理过的入度为0的结点 */
    				break;
    			}
    		}
    	}
    }
    
    void Output()
    {
    	int i;
    	for (i = 0; i < list.iNum; i++)
    	{
    		if (0 == i)
    		{
    			printf("%d", list._array[i]);
    		}
    		else
    		{
    			printf(" %d", list._array[i]);
    		}
    	}
    	printf("\n");
    }
    
    int main()
    {
    	while (~scanf("%d %d", &tpGraphNode.iNumTeam, &iNumMatch))
    	{
    		Init();
    		Input();
    		TopologicalSort();
    		Output();
    	}
    	return 0;
    }
    


    /**************************************************************************
                      原文来自博客园——Submarinex的博客: www.cnblogs.com/submarinex/               
      *************************************************************************/

  • 相关阅读:
    .NET:如何应对边界异常?
    由极点五笔到QQ五笔的转换想到的
    【转】七个受用一生的心理寓言
    proverb: better late than never
    背单词软件supermemo从2006版升级到2008版
    今天解决一个异步刷新TreeView的问题
    开始尝试换成Windows 7了
    southpaw
    用supermemo背单词达到6000词条
    Averse, Adverse
  • 原文地址:https://www.cnblogs.com/submarinex/p/2159621.html
Copyright © 2011-2022 走看看