zoukankan      html  css  js  c++  java
  • 2019/4/22 拓扑排序的高效写法. 模板题HDU1285:确定比赛名次

    传送门

    Problem Description

    有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

    Input

    输入有若干组,每组中的第一行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

    Output

    给出一个符合要求的排名。输出时队伍号之间有空格,最后一名后面没有空格。

    其他说明:符合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保一定能有一个符合要求的排名。

    Sample Input

    4 3
    1 2
    2 3
    4 3
    Sample Output
    1 2 4 3

    这里默认为大家都已经了解了拓扑排序的思想和基本算法, 矩阵法(时间复杂度高,O(N2))以及队列优化法(时间复杂度O(N * M)),

    在这里在给出一种写法, 我觉得比较实用, 效率也比较高。

    优先队列+链式前向星。

    用优先队列的原因是因为拓扑排序出来的结果是不唯一的, 假如题目要求要从小到大或者从大到小都可以直接控制。
     
    HDU上用C++会CE错误, 要用G ++提交。
     
    #include<stdio.h>
    #include<queue>
    #include<string.h>
    #include<vector>
    using namespace std;
    
    int cnt, head[501], n;
    int in[501];
    priority_queue<int, vector<int>, greater<int> >Q;
    
    struct Edge
    {
    	int to, next;
    }edge[250 * 500];
    
    void add(int u, int v)
    {
    	edge[++ cnt].to = v;
    	edge[cnt].next = head[u];
    	head[u] = cnt;
    }
    
    void topo_sort()
    {
    	int sum = 0;
    	int ans[501];
    	for(int i = 1; i <= n; i ++) //入度为0的点入队 
    		if(!in[i])
    			Q.push(i);
    	while(!Q.empty())
    	{
    		int temp = Q.top();//找到一个入度为0的点temp 
    		ans[++ sum] = temp;//存答案 
    		Q.pop();
    		for(int i = head[temp]; i != 0; i = edge[i].next)
    		{
    			int to = edge[i].to;
    			in[to] --;//与temp为弧尾的点的入度 - 1,相当于在图中将temp点删除 
    			if(!in[to])//若temp为弧尾的点的入度变为0,那么入队 
    			{
    				Q.push(to);
    			}
    		}
    	}
    	printf("%d", ans[1]);//按照格式输出 
    	for(int i = 2; i <= sum; i ++)
    	{
    		printf(" %d", ans[i]);
    	}
    	printf("\n");
    }
    
    int main()
    {
    	int m, a, b;
    	while(scanf("%d%d", &n, &m)!=EOF)
    	{
    		cnt = 0;
    		while(!Q.empty())
    			Q.pop();
    		memset(head, 0, sizeof(head));
    		memset(in, 0, sizeof(in));
    		for(int i = 1; i <= m; i ++)
    		{
    			scanf("%d%d", &a, &b);
    			add(a, b);
    			in[b] ++;  //存每个点的入度 
    		}
    		topo_sort();
    	}
    	return 0;
    }
    

      

           
     
  • 相关阅读:
    any、some、all for sql
    Date CONVERT() 函数
    Config Database
    移动master 数据库
    使用 OpenRowSet 和 OpenDataSource 访问 Excel 972007
    动态管理视图和函数
    SQL Server 2005 Merge Replication Step by Step Procedure
    系统试图(返回表所有记录数及所有的 identity 列)
    js if without curly brackets bug All In One
    Web3 All In One
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/10749733.html
Copyright © 2011-2022 走看看