正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)

确定比赛名次

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 16   Accepted Submission(s) : 9

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队。

逃生

Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 20   Accepted Submission(s) : 9

Problem Description

糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。

现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。
同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。

负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。

那么你就要安排大家的顺序。我们保证一定有解。

Input

第一行一个整数T(1 <= T <= 5),表示测试数据的个数。 然后对于每个测试数据,第一行有两个整数n(1 <= n <= 30000)和m(1 <= m <= 100000),分别表示人数和约束的个数。 然后m行,每行两个整数a和b,表示有一个约束a号必须在b号之前。a和b必然不同。

Output

对每个测试数据,输出一行排队的顺序,用空格隔开。

Sample Input

1
5 10
3 5
1 4
2 5
1 2
3 4
1 4
2 3
1 5
3 5
1 2

Sample Output

1 2 3 4 5

Output

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

Sample Input

4 3
1 2
2 3
4 3

Sample Output

1 2 4 3

两者看着并没什么大的区别。

但前者是用最普通的拓扑排序,而后者需要反着来。

对普通的拓扑排序,由于题目需要按序,所以使用优先队列即可,将没有 前点 (即入度)的点入列,用这几个点的路径减少其他点的入度,然后将入度为0的入队,就行了。

而对于第二题,则由于要求的不同(先考虑1在尽量前,再考虑2尽量前。。。),我们将后点设为入度,同样的方法排序,反向输出即可。

可能有人会觉得两者差不多。

这里给个例子。

5 2(n,m)

5 1

4 2

正向给出的答案是3 4 2 5 1

反向给出的答案是1 2 3 4 5

理解一下

以下是代码:

1285 确定比赛名次:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define me(a,b) memset(a,b,sizeof(a))
#define N 5100
typedef long long ll;
using namespace std;

int in[N],head[N],n,m,cnt,s,e;
priority_queue<int,vector<int>,greater<int> > q;
vector<int> ans;

struct co
{
      int e,pre;
}mp[N];

void init()
{
      me(head,-1);
      cnt=0;
      me(in,0);
      while(!q.empty())
            q.pop();
      ans.clear();
}

void add(int ss,int ee)
{
      mp[cnt].e=ee;
      mp[cnt].pre=head[ss];
      head[ss]=cnt++;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m))
    {
          init();
          while(m--)
          {
                  scanf("%d%d",&s,&e);
                in[e]++;
                add(s,e);
          }
          for(int i=1;i<=n;i++)
          {
                if(in[i]==0)
                {
                      q.push(i);
                }
          }
          while(!q.empty())
          {
                int f=q.top();
                  ans.push_back(f);
                q.pop();
                for(int i=head[f]; i!=-1; i=mp[i].pre)
                {
                      in[mp[i].e]--;
                      if(in[mp[i].e]==0)
                      {
                              q.push(mp[i].e);
                      }
                }

          }
          for(int i=0;i<ans.size();i++)
          {
                if(i)
                  cout<<‘ ‘;
                cout<<ans[i];
          }
          cout<<endl;
    }
}

4857:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define me(a,b) memset(a,b,sizeof(a))
#define N 100010
typedef long long ll;
using namespace std;

int in[30100],head[N],n,m,cnt,s,e;
priority_queue<int> q;
vector<int> ans;

struct co
{
      int e,pre;
}mp[N];

void init()
{
      me(head,-1);
      me(in,0);
      cnt=0;
      while(!q.empty())
            q.pop();
      ans.clear();
}

void add(int ss,int ee)
{
      mp[cnt].e=ee;
      mp[cnt].pre=head[ss];
      head[ss]=cnt++;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    cin>>T;
    while(T--)
    {
          init();
          scanf("%d%d",&n,&m);
          while(m--)
          {
          scanf("%d%d",&s,&e);
                in[s]++;
                add(e,s);
          }
          for(int i=1;i<=n;i++)
          {
                if(in[i]==0)
                {
                      q.push(i);
                }
          }
          while(!q.empty())
          {
                int f=q.top();
                  ans.push_back(f);
                q.pop();
                for(int i=head[f]; i!=-1; i=mp[i].pre)
                {
                      in[mp[i].e]--;
                      if(in[mp[i].e]==0)
                      {
                              q.push(mp[i].e);
                      }
                }

          }
          for(int i=ans.size()-1;i>-1;i--)
          {
                cout<<ans[i];
                if(i)
                  cout<<‘ ‘;
          }
          cout<<endl;
    }
}

原文地址:https://www.cnblogs.com/zgncbsylm/p/10727395.html

时间: 2024-09-28 19:01:35

正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)的相关文章

[ACM] hdu 1285 确定比赛名次 (拓扑排序)

确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10358    Accepted Submission(s): 4046 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直

HDU 1285 确定比赛名次(拓扑排序+优先队列)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前.现在请你编程序确定排名. Input 输入有若干组,每组中的第一行为二个数N(1<=N<

HDU 1285 确定比赛名次(拓扑排序模板)

题意还是比较容易理解的,关键要看到后面的:合条件的排名可能不是唯一的,此时要求输出时编号小的队伍在前: 思路:这道题就是拓扑排序的经典应用了,用队列做的考虑优先编号小的出队就可以了. 拓扑排序: 拓扑排序是对有向无回路图(DAG)顶点的一种排序,它使得如果存在从u到v的有向路径,那么满足序列中u在v前. 所以我们的算法可以描述为这样一个过程: 1.找到整个图中所有的度为0的点,将这些点压进队列(栈)中 2.从队列(栈)中取出一点,输出,将该点及它的边删除,找到它所指向的点,如果改点是一个原点(删

ACM: HDU 1285 确定比赛名次 - 拓扑排序

HDU 1285 确定比赛名次 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前.现在请你编程序确定排名

HDU 1285——确定比赛名次(拓扑排序入门)

确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 12182    Accepted Submission(s): 4861 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直

hdu 1285 确定比赛名次 (模板题)

确定比赛名次 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 11353    Accepted Submission(s): 4525 Problem Description 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接

HDU[1285]确定比赛名次 拓扑排序

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285 题目大意:某人知道N个队伍M场比赛的胜负结果,要求输出N个队伍的名次(id为第二关键字). 核心思想:转化为图论问题,进行拓扑排序.步骤1.选定入度为0的点 2.删除该点与关联边 3.重复该过程 代码如下: //拓扑排序 (1.选入度为0的点.2.删除该点及关联边 3.重复该过程) #include <iostream> #include <memory.h> using nam

HDU 1285 确定比赛名次 (拓扑排序)

链接 :  http://acm.hdu.edu.cn/showproblem.php?pid=1285 拓扑排序模板 . #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <sstream> #include <cstdio> #include <vector> #include <cm

HDU 1285 确定比赛名次(拓扑排序基础题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1285 题目: 有N个比赛队(1<=N<=500),编号依次为1,2,3,....,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前.现在请你编程序确定排名. Input 输入有若干组,每组中的第一行为二个数N(1<=N<=500),M:其中N表示队