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

题目概述

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

解题报告

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

示例程序

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

#include
#include
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''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;
}

你可能感兴趣的:(BZOJ题解,堆,拓扑)