luogu P3243 [HNOI2015]菜肴制作

这题一看就知道和拓扑序有关

考虑拓扑排序的时候每次取队列里最小的数进行排序

然后就\(\mathcal{GG}\)了,因为这样只能使字典序最小,而并不能保证题目中要求的每个编号的数要在满足前面数尽量在前面的同时自己尽量在前面

例如

Input
5 2
5 2
4 3
Wrong Output
1 4 3 5 2
Correct Output
1 5 2 4 3

我这里先是想从小到大依次考虑每个数,把这个数在\(DAG\)上的前驱全部用前面方法贪心取出,然后取出该数,但这样做比较复杂

然后如果把这个过程完全反过来呢?我们可以发现这其实就是该\(DAG\)的反图进行拓扑排序,同时使得字典序最大

然后就随便氵啦(逃

#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register

using namespace std;
const int N=100000+10;
il LL rd()
{
    re LL x=0,w=1;re char ch;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[N],nt[N],hd[N],tot=1,d[N];
il void add(int x,int y){++tot;to[tot]=y;nt[tot]=hd[x];hd[x]=tot;}
int n,m,a[N],tt;

int main()
{
  int T=rd();
  while(T--)
    {
      memset(hd,0,sizeof(hd));tot=1;
      memset(d,0,sizeof(d));
      n=rd(),m=rd();tt=0;
      for(re int i=1;i<=m;i++)
        {
          int x=rd(),y=rd();
          ++d[x];
          add(y,x);
        }
      priority_queue<int> q;
      for(re int i=1;i<=n;i++)
        if(!d[i]) q.push(i);
      while(!q.empty())
        {
          int x=q.top();
          q.pop();
          a[++tt]=x;
          for(re int i=hd[x];i;i=nt[i])
            {
              int y=to[i];
              --d[y];
              if(!d[y]) q.push(y);
            }
        }
      if(tt<n) puts("Impossible!");
      else {for(re int i=n;i>=1;i--) printf("%d ",a[i]);putchar('\n');}
    }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/smyjr/p/9456361.html