【拓扑+堆】BZOJ4010(HNOI2015)[菜肴制作]题解

来源:互联网 发布:mac系统可以装ps吗 编辑:程序博客网 时间:2024/06/05 19:17

题目概述

给出一张 n 个点 m 条边的拓扑图,假设第 i 个点是第 ai 个出队的,求一种合法方案使得 {an} 的字典序最小。

解题报告

好妙的题……因为题目里的要求比较难实现,所以我们可以倒着来建反图,那么问题变成了让编号大的点尽量先出队(而不是求字典序最小)。最后倒着输出就行了。

示例程序

刚开始以为是以前做过的简单题,于是盗了代码……码风奇怪不要介意QAQ

#include<cstdio>#include<cstring>const int maxn=100005,maxm=100005;int n,tot,nxt[maxm],son[maxm],lnk[maxn],f[maxn],heap_b[maxn],len,ans[maxn];inline bool readi(int &x){    int tot=0,f=1;    char ch=getchar();    while ('9'<ch||ch<'0') {if (ch=='-') f=-f;ch=getchar();}    while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=getchar();    x=tot*f;    return ch==10||ch==13||ch==EOF;}void add2(int x,int y){    tot++;    son[tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}void swapi(int &x,int &y){    int t=x;x=y;y=t;}void put1(int x){    int son;    heap_b[++len]=x;son=len;    while (son!=1&&heap_b[son]>heap_b[son>>1])    {        swapi(heap_b[son],heap_b[son>>1]);        son>>=1;    }}int get1(){    int fa=1,son,x;    x=heap_b[1];heap_b[1]=heap_b[len--];    while (2*fa<=len)    {        if (2*fa+1>len||heap_b[2*fa]>heap_b[2*fa+1]) son=2*fa; else son=2*fa+1;        if (heap_b[son]>heap_b[fa])        {            swapi(heap_b[son],heap_b[fa]);            fa=son;        } else break;    }    return x;}int main(){    int i,j,m,x,y,te,now=0;    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    for (readi(te);te;te--)    {        readi(n);readi(m);now=n;        tot=0;memset(lnk,0,sizeof(lnk));memset(f,0,sizeof(f));        for (i=1;i<=m;i++) readi(x),readi(y),f[x]++,add2(y,x);        len=0;for (i=1;i<=n;i++) if (!f[i]) put1(i);        while (len)        {            x=get1();ans[now--]=x;            for (j=lnk[x];j;j=nxt[j])            {                f[son[j]]--;                if (!f[son[j]]) put1(son[j]);            }        }        if (now) printf("Impossible!\n"); else        {            for (i=1;i<=n;i++) printf("%d ",ans[i]);            putchar('\n');        }    }    return 0;}