SOJ 4110: PE class

题目链接:http://cstest.scu.edu.cn/soj/problem.action?id=4110


题目大意:

拓扑排序。

但是本题的要求不是拓扑序列字典序最小,

而是1~N号球所对应的排序后的位置构成的序列字典序最小,

也就是,在满足编号1尽量靠前的条件下,编号2要尽量靠前,在满足前两个条件下,编号3尽量靠前,依次类推。


算法:

反向思维,倒序拓扑。

每次让序号大的球尽量往后排。

因为从后往前排的时候,
决定的位置就是越来越重要的,
然后不断有新的顶点入队,
如果这里面有更小的顶点,就可以把它放到前面去。


代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

int head[210],d[210],ans[210],top,E;

struct
{
  int u,v,w,nxt;
} edge[41000];

void addedge(int u,int v)
{
  edge[E].u=u;
  edge[E].v=v;
  edge[E].nxt=head[u];
  head[u]=E++;
}


int main()
{
  int n,m,cas;
  scanf("%d",&cas);
  while(cas--)
    {
      scanf("%d%d",&n,&m);
      memset(head,-1,sizeof(head));
      memset(d,0,sizeof(d));
      E=0;
      while(m--)
        {
          int u,v;
          scanf("%d%d",&u,&v);
          addedge(v,u);
          d[u]++;
        }
      priority_queue<int>qq;
      for(int i=1; i<=n; i++)
        {
          if(!d[i])
            qq.push(i);
        }
      top=n;
      while(!qq.empty())
        {
          int u=qq.top();
          qq.pop();
          ans[u]=top--;
          for(int i=head[u]; i!=-1; i=edge[i].nxt)
            {
              d[edge[i].v]--;
              if(!d[edge[i].v])
                qq.push(edge[i].v);
            }
        }
      if(top)
        {
          puts("-1\n");
          continue;
        }
      for(int i=1; i<=n; i++)
        {
          if(i>1)putchar(' ');
          printf("%d",ans[i]);
        }
      puts("\n");
    }
  return 0;
}


你可能感兴趣的:(SOJ 4110: PE class)