BZOJ 4010 菜餚製作(拓撲排序)

題目鏈接: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章