hdoj1285 确定比赛名次 topo排序 Kahn算法 (新手向)

来源:互联网 发布:ios矩阵潜袭 编辑:程序博客网 时间:2024/04/29 03:11

题目:

确定比赛名次

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 25983    Accepted Submission(s): 10468


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 31 22 34 3
 

Sample Output
1 2 4 3
 

Author
SmallBeer(CML)
 

Source
杭电ACM集训队训练赛(VII)
 

Recommend
lcy   |   We have carefully selected several similar problems for you:  2647 3342 1811 2066 1102 

第一道拓扑排序的题,让我酝酿一下自己的情感,叫出“hello,world!”

什么是拓扑排序?

有向图的拓扑排序或拓扑排序是其顶点的线性排序,使得对于从顶点 u 到顶点 v 的每个有向边 uv,u 在排序中都在 v 之前。---来自维基百科

大概就是这样一个问题,你穿衣服,有鞋,裤子,袜子,衬衣。你先穿哪一个的问题。就是说,你执行的任务有一个先后顺序。对这些任务的执行顺序进行排序。争对上面这个问题,肯定是先裤子,再袜子,再鞋。衬衣这几个的关系倒无所谓,想啥时候穿,就啥时候穿。(这个涉及到全序,偏序的概念)

什么条件才能进行拓扑排序?

有向无环图(DAG, Directed Acyclic Graph)。这个也很好理解,比如我告诉你A在B前,B在A前,你该怎么排?从而topo排序,另外一个用法就是判断有没有环。

怎么topo排序?

这里的是Kahn算法,还有基于dfs的也可以摆渡一下。

Kahn算法的描述:

L← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edges
while S is non-empty do
    remove a node n from S
    insert n into L
    foreach node m with an edge e from nto m do
        remove edge e from thegraph
        ifm has no other incoming edges then
            insert m into S
if graph has edges then
    return error (graph has at least onecycle)
else 
    return L (a topologically sortedorder)

我们需要维护一个入度为0的集合S,然后取出S中一个点,删除所有与之相邻的边,相应的这些边指向的点的入度应该减少1,如果入度为0,则加入S。

判环:就是当最后S为空,而还剩余了图时就有环了。一切尽在上面的那段说明中。

复杂度:O(V+E)

code(基于hdoj1285):

对了,这道题,要求满足条件序号最小。那么就用优先队列搞搞就可以了。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=500+10;
int map[MAXN][MAXN];
int indegree[MAXN];
 vector<int>G[MAXN];
int main(void){
    int N,M;
    while(~scanf("%d%d",&N,&M)){
        priority_queue<int,vector<int> ,greater<int> >q;
        while(!q.empty())q.pop();
        memset(map,0,sizeof(map));
        memset(indegree,0,sizeof(indegree));
        for(int i=0;i<M;++i){
            int a,b;scanf("%d%d",&a,&b);
            if(!map[a][b]){//为了防止重边
                map[a][b]=1;
                G[a].push_back(b);
                indegree[b]++;
            }
        }


        for(int i=1;i<=N;++i)
            if(indegree[i]==0)q.push(i);
        bool isFirst=true;//为了满足格式要求
        while(!q.empty()){
            int no=q.top();q.pop();
            printf(isFirst?"%d":" %d",no);
            isFirst=false;
            for(int i=0;i<G[no].size();++i){
                int v=G[no][i];
                indegree[v]--;
                if(indegree[v]==0)q.push(v);
            }
            G[no].clear();//删除所有no指向的边
        }
        printf("\n");
    }
}

————————介于WA与AC之间的分割线———————————————————————————————

关于偏序与全序:

一下内容转自:dm_vincent  侵删

偏序/全序关系:

偏序和全序实际上是离散数学中的概念。

这里不打算说太多形式化的定义,形式化的定义教科书上或者上面给的链接中就说的很详细。

 

还是以上面选课的例子来描述这两个概念。假设我们在学习完了算法这门课后,可以选修机器学习或者计算机图形学。这个或者表示,学习机器学习和计算机图形学这两门课之间没有特定的先后顺序。因此,在我们所有可以选择的课程中,任意两门课程之间的关系要么是确定的(即拥有先后关系),要么是不确定的(即没有先后关系),绝对不存在互相矛盾的关系(即环路)以上就是偏序的意义,抽象而言,有向图中两个顶点之间不存在环路,至于连通与否,是无所谓的。所以,有向无环图必然是满足偏序关系的。

 

理解了偏序的概念,那么全序就好办了。所谓全序,就是在偏序的基础之上,有向无环图中的任意一对顶点还需要有明确的关系(反映在图中,就是单向连通的关系,注意不能双向连通,那就成环了)可见,全序就是偏序的一种特殊情况。回到我们的选课例子中,如果机器学习需要在学习了计算机图形学之后才能学习(可能学的是图形学领域相关的机器学习算法……),那么它们之间也就存在了确定的先后顺序,原本的偏序关系就变成了全序关系。

 

实际上,很多地方都存在偏序和全序的概念。

比如对若干互不相等的整数进行排序,最后总是能够得到唯一的排序结果(从小到大,下同)。这个结论应该不会有人表示疑问吧:)但是如果我们以偏序/全序的角度来考虑一下这个再自然不过的问题,可能就会有别的体会了。

 

那么如何用偏序/全序来解释排序结果的唯一性呢?

我们知道不同整数之间的大小关系是确定的,即1总是小于4的,不会有人说1大于或者等于4吧。这就是说,这个序列是满足全序关系的。而对于拥有全序关系的结构(如拥有不同整数的数组),在其线性化(排序)之后的结果必然是唯一的。对于排序的算法,我们评价指标之一是看该排序算法是否稳定,即值相同的元素的排序结果是否和出现的顺序一致。比如,我们说快速排序是不稳定的,这是因为最后的快排结果中相同元素的出现顺序和排序前不一致了。如果用偏序的概念可以这样解释这一现象:相同值的元素之间的关系是无法确定的。因此它们在最终的结果中的出现顺序可以是任意的。而对于诸如插入排序这种稳定性排序,它们对于值相同的元素,还有一个潜在的比较方式,即比较它们的出现顺序,出现靠前的元素大于出现后出现的元素。因此通过这一潜在的比较,将偏序关系转换为了全序关系,从而保证了结果的唯一性。

 

拓展到拓扑排序中,结果具有唯一性的条件也是其所有顶点之间都具有全序关系。如果没有这一层全序关系,那么拓扑排序的结果也就不是唯一的了。在后面会谈到,如果拓扑排序的结果唯一,那么该拓扑排序的结果同时也代表了一条哈密顿路径。


———————————下面内容来自百度作业帮,侵删————————————————————————

偏序只对部分元素成立关系R,全序对集合中任意两个元素都有关系R.
例如:
集合的包含关系就是半序,也就是偏序,因为两个集合可以互不包含;
而实数中的大小关系是全序,两个实数必有一个大于等于另一个;
又如:复数中的大小就是半序,虚数不能比较大小.


原创粉丝点击