1. 程式人生 > >洛谷3243 [HNOI2015]菜肴制作

洛谷3243 [HNOI2015]菜肴制作

倒序輸出 problem pac www names mem show sizeof 反向

題目戳這裏
Solution


錯誤的想法:正向建圖,然後從入度為0的點選出最小u的開始輸出,然後找出u連接的點v,並把v的度數減一,再次把入度為0的點加入小根堆,這樣顯然有錯,因為只能局部保證最小,後面的情況便無法確定。
Hack數據: n=3,m=1 限制:<3,1>
按照之前的思路,3和2的入度為0,那麽取出更小的2,所以答案為2,3,1,但是答案顯然為3,2,1。
那麽怎麽辦? 正向建圖不行,那麽我們就反向建圖,再倒序輸出,這樣保證越大的越晚輸出,就OK了!
具體做法:本蒟蒻因為topsort用得不熟,所以只好用大根堆模擬 ,首先把入讀為0的點加入大根堆,每次取出u(因為是大根堆,所以保證u是堆中最大的),再找出u連接的點v,並把v的度數減一,再次把入度為0的點加入大根堆,最後反向輸出。
PS:雖然思路比較難想,但代碼實現還是很容易的!



Coding

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5;
struct road
{
    int to,next;
}e[N*5];
priority_queue <int> q;
int cntt,ans[N],head[N],n,m,in[N],out[N];
void add(int x,int y)
{
    cntt++;
    e[cntt].to=y;
    e[cntt].next=head[x];
    head[x]=cntt;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cntt=0;
        memset(head,0,sizeof(head));
        memset(in,0,sizeof(in));
        int cnt=0;
        cin>>n>>m;
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(y,x);
            in[x]++;
        }
        for(int i=1;i<=n;i++)
            if(in[i]==0) q.push(i);
        int flag=0;
        while(1)
        {
            cnt++;      
            int x=q.top();
            ans[cnt]=x;
            q.pop();
            for(int i=head[x];i;i=e[i].next)
            {
                int v=e[i].to;
                in[v]--;
                if(in[v]==0) q.push(v);
            }
            if(cnt==n) break ;
            if(q.empty()) {cout<<"Impossible!"<<endl; flag=1;break;}
        }
        if(!flag)
        {
            for(int i=n;i>=1;i--) 
                printf("%d ",ans[i]);
            cout<<endl;
        }
    }
    return 0;
}

洛谷3243 [HNOI2015]菜肴制作