BZOJ4010 [HNOI2015]菜肴制作

本文介绍了一道关于菜肴制作顺序的问题,通过反向建边并运用拓扑排序的方法求解最优顺序。针对输入的不同情况,给出了具体实现代码及解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

标签:拓扑排序

题目

题目传送门

题目描述

知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴。 ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为1。

由于菜肴之间口味搭配的问题,某些菜肴必须在另一些菜肴之前制作,具体的,一共有 M 条形如”i 号菜肴’必须’先于 j 号菜肴制作“的限制,我们将这样的限制简写为

输入输出格式

输入格式

第一行是一个正整数D,表示数据组数。 接下来是D组数据。 对于每组数据: 第一行两个用空格分开的正整数N和M,分别表示菜肴数目和制作顺序限制的条目数。 接下来M行,每行两个正整数x,y,表示”x号菜肴必须先于y号菜肴制作“的限制。(注意:M条限制中可能存在完全相同的限制)

输出格式

输出文件仅包含 D 行,每行 N 个整数,表示最优的菜肴制作顺序,或者“Impossible!“表示无解(不含引号)。

输入输出样例

输入样例#1

3
5 4
5 4
5 3
4 2
3 2
3 3
1 2
2 3
3 1
5 2
5 2
4 3

输出样例#1

1 5 3 4 2 
Impossible! 
1 5 2 4 3

说明

【样例解释】

第二组数据同时要求菜肴1先于菜肴2制作,菜肴2先于菜肴3制作,菜肴3先于

菜肴1制作,而这是无论如何也不可能满足的,从而导致无解。

100%的数据满足N,M<=100000,D<=3。

分析

反向建边跑拓扑排序!

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read()
{
    ll f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=1e5+6;
priority_queue<int> que;
struct edge{int to,next;}e[maxn<<1];
int du[maxn],last[maxn],n,T,m,cnt,ans[maxn];
void insert(int u,int v){
    e[++cnt]=(edge){v,last[u]};last[u]=cnt;
}
int main()
{
    T=read();
    while(T--){
        cnt=0;mem(e,0);mem(last,0);mem(du,0);
        n=read(),m=read();
        rep(i,1,m){int u=read(),v=read();insert(v,u);du[u]++;}
        int now=0;
        rep(i,1,n)if(!du[i])que.push(i);
        while(!que.empty()){
            int x=que.top();que.pop();
            ans[++now]=x;
            reg(x){
                du[e[i].to]--;
                if(!du[e[i].to])que.push(e[i].to);
            }
        }
        if(now==n){
            dep(i,n,1)printf("%d ",ans[i]);printf("\n");
        }else puts("Impossible!");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值