P3243 [HNOI2015]菜肴制作

题意

这题上来很容易想去求最小的拓扑序,即将队列换成堆的做法。

然而题目要求小的数尽量靠前,我们就拿样例的第三个说:

字典序最小:\(14352\)

正解:\(15243\)

因为正解中\(2\)比字典序最小拓扑序的更靠前(\(3<5\))。

也就说越小的数越应该在前面,之后再考虑其他的数,那么正着不好想不妨反过来:越大的数越应该靠后。

于是建反图求字典序最大的拓朴序,之后反着输出即可。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
struct edge
{
    int to,nxt;
}e[maxn];
int T,n,m,cnt,tot;
int head[maxn],deg[maxn],a[maxn];
inline void add(int u,int v)
{
    e[++cnt].nxt=head[u];
    head[u]=cnt;
    e[cnt].to=v;deg[v]++;
}
void init()
{
    memset(head,0,sizeof(head));
    memset(deg,0,sizeof(deg));
    cnt=tot=0;
}
void topsort()
{
    priority_queue<int> q;
    for(int i=1;i<=n;i++) if(!deg[i]) q.push(i);
    while(!q.empty())
    {
        int x=q.top();q.pop();a[++tot]=x;
        for(int i=head[x];i;i=e[i].nxt)
        {
            int y=e[i].to;deg[y]--;
            if(!deg[y]) q.push(y);
        }
    }
    if(tot<n) printf("Impossible!");
    else for(int i=tot;i;i--) printf("%d ",a[i]);
    puts("");
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) 
        {
            int u,v;scanf("%d%d",&u,&v);
            add(v,u);
        }
        topsort();
    }
    return 0;
}
posted @ 2019-12-21 18:10  nofind  阅读(101)  评论(0编辑  收藏  举报