BZOJ 4010 菜肴制作(拓扑排序)

来源:互联网 发布:譬如工画师 不能知自心 编辑:程序博客网 时间:2024/06/06 15:44

题目链接:BZOJ 4010
题解:
拓扑排序是比较明显的,两种思路:

  • 正着,每次找字典序最小的
  • 倒着,每次找字典序最大的

如果有限制条件<4,1>,那么最优解是(4,1,2,3),但正着找字典序最小找到的却是 (2,3,4,1),因此正着行不通。反着的正确性想想似乎有道理,反向建边,每次字典序最大的放到最后,就能让字典序小的尽量靠前了吧。(我不会证明QwQ……)
code(代码还是比较简单的(⊙v⊙))

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<queue>#include<algorithm>using namespace std;int t,tot,a[100005],head[110000],in[110000];priority_queue < pair<int,int> , vector<pair<int,int> > >q;bool vis[100001];struct edge{    int to,ne;}e[220000];void push(int x,int y){    e[++tot].to=y; e[tot].ne=head[x]; head[x]=tot; in[y]++;}using namespace std;int main(){    scanf("%d",&t);    int n,m;    while (t--)    {        memset(vis,false,sizeof(vis));        memset(a,0,sizeof(a));        memset(in,0,sizeof(in));        memset(head,0,sizeof(head));        tot=0;        scanf("%d%d",&n,&m);        for (int i=1;i<=m;i++)        {            int x,y;            scanf("%d%d",&x,&y);            push(y,x);        }        int sum=0;        for (int i=1;i<=n;i++)         if (in[i]==0) q.push(make_pair(i,0));        int cnt=0;        while (!q.empty())        {            int now=q.top().first; q.pop();            if (vis[now]) continue;            vis[now]=true;            a[++cnt]=now;            for (int i=head[now];i;i=e[i].ne)            {                int v=e[i].to;                in[v]--;                if (in[v]==0) q.push(make_pair(v,0));            }        }        if (cnt!=n) printf("Impossible!\n");         else          {              for (int i=1;i<=n;i++)               printf("%d ",a[n-i+1]);              printf("\n");          }    }    return 0;}