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

Posted zgncbsylm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了正向与反向拓扑排序的区别(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;
    }
}

 

 

以上是关于正向与反向拓扑排序的区别(hdu 1285 确定比赛名次和hdu 4857 逃生)的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

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

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

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