HDU1285-确定比赛名次-拓扑排序板子题

有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


这个是按照自己的理解写的,样例过了,可是WA
 1 #include<stdio.h>
 2 #include<cmath>
 3 #include<string.h>
 4 #include<iostream>
 5 using namespace std;
 6 
 7 
 8 int a[550][550];
 9 int rudu[550];
10 int ans[550];
11 
12 int main()
13 {
14     int n,m;
15     while(~scanf("%d %d",&n,&m))
16     {
17         memset(a,0,sizeof(a));
18         memset(rudu,0,sizeof(rudu));
19         memset(ans,0,sizeof(ans));
20         int aa,bb;
21         for(int i=0; i<m; i++)
22         {
23             scanf("%d %d",&aa,&bb);
24             //a[aa]=bb;
25             a[aa][bb]++;
26             rudu[bb]++;
27             //  dis[bb]=1;
28         }
29 
30         int p=0;
31         for(int i=1; i<=n; i++)
32         {
33             int k;
34             for(int j=1; j<=n; j++)
35             {
36                 if(rudu[j]==0)
37                 {
38                     //   printf("%d***\n",j);
39                     rudu[j]--;
40                     ans[p++]=j;
41                     k=j;
42                     break;
43                 }
44             }
45 
46             for(int j=1; j<=n; j++)
47             {
48                 if(a[k][j])
49                 {
50                     a[k][j]--;
51                     rudu[j]--;
52                 }
53             }
54         }
55 
56         //   cout<<rudu[4]<<endl;-4
57 
58         for(int i=0;i<p-1;i++)
59             printf("%d ",ans[i]);
60         printf("%d\n",ans[p-1]);
61     }
62     return 0;
63 }
View Code

 wa原因:

如果碰到

1 2

1 2出现两次及多次的时候,按照错误的代码2会被加两次,而实际只需要加一次入度即可。所以相当于标记和未标记两种情况,而不需要多次++

 

这个是后来周赛结束改的AC了

#include<stdio.h>
#include<cmath>
#include<string.h>
#include<iostream>
using namespace std;


int a[550][550];
int rudu[550];
int ans[550];

int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        memset(a,0,sizeof(a));
        memset(rudu,0,sizeof(rudu));
        memset(ans,0,sizeof(ans));
        int aa,bb;
        for(int i=0; i<m; i++)
        {
            scanf("%d %d",&aa,&bb);
            //a[aa]=bb;
//            a[aa][bb]++;不对
//            rudu[bb]++;不对
            //  dis[bb]=1;
            if(a[aa][bb]==0)
            {
                a[aa][bb]=1;
                rudu[bb]++;
            }
        }

        int p=0;
        for(int i=1; i<=n; i++)
        {
            int k;
            for(int j=1; j<=n; j++)
            {
                if(rudu[j]==0)
                {
                    //   printf("%d***\n",j);
                    rudu[j]--;
                    ans[p++]=j;
                    k=j;
                    break;
                }
            }

            for(int j=1; j<=n; j++)
            {
                if(a[k][j])
                {
                    a[k][j]=0;
//                    a[k][j]--;
                    rudu[j]--;
                }
            }
        }

        //   cout<<rudu[4]<<endl;-4

        for(int i=0;i<p-1;i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[p-1]);
    }
    return 0;
}

 

 

正好整理一下拓扑排序入门的知识点:

拓扑排序的优点及适用场景:

       快速排序是不稳定的,这是因为最后的快排结果中相同元素的出现顺序和排序前不一致了。如果用偏序的概念可以这样解释这一现象:相同值的元素之间的关系是无法确定的。因此它们在最终的结果中的出现顺序可以是任意的。

       而对于诸如插入排序这种稳定性排序,它们对于值相同的元素,还有一个潜在的比较方式,即比较它们的出现顺序,出现靠前的元素大于出现后出现的元素。因此通过这一潜在的比较,将偏序关系转换为了全序关系,从而保证了结果的唯一性。而拓扑排序就是一种将偏序转换为全序的一种算法。

补充两个概念,偏序和全序:

偏序:有向图中两个顶点之间不存在环路,至于连通与否,是无所谓的。

全序:就是在偏序的基础之上,有向无环图中的任意一对顶点还需要有明确的关系(反映在图中,就是单向连通的关系,注意不能双向连通,那就成环了)。

意思就是讲,一个不确定的偏序关系经全序后就有一种确定的先后顺序了。

既然有先后,那么在实际生活中的选课问题,比如大一时一定要修完这门课,大二才学第二门课,这种排课问题就是拓扑排序问题。

总结以上,拓扑排序实质上就是一种偏序到全序的排序算法。

 

定义:
只有有向无环图(Directed Acyclic Graph,简称DAG )才有拓扑排序。 
DAG必至少有一个入度为零的点和一个出度为零的点。

wikipedia中关于拓扑排序的定义:在拓扑排序中,对于任意一个有向边的起点和终点,在排序后起点总是在终点前。 

 

在DAG中如果对于任意两点都可以找到一条路径使二者连通,则称该图是全序的,否则为偏序。 
全序DAG的拓扑排序是该图的一条哈密顿路径,即经过该图的所有顶点。

算法:
常用的有Kahn算法和DFS算法。

 

附上我入门拓扑排序看的文章:

https://blog.csdn.net/qq_41713256/article/details/80805338

 

转载于:https://www.cnblogs.com/OFSHK/p/11511010.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值