bzoj4010: [HNOI2015]菜肴制作

3 篇文章 0 订阅

题面在这里

题意:

求一个n的排列,有一些限制

做法:

注意这个不同于求字典序最小。
一个例子是n=4,限制有<3,1>,<2,4>
答案应该是3124
如果是字典序最小是2431

我们发现编号小的尽量在前,相当于将序列反过来以后,字典序要最大。
这个很好理解,因为假如你反着来字典序没有最大,肯定会有一个较小的数在后面。
而事实上是可以将它提前的。

所以原问题转化成了反向建图,求字典序最大的拓扑序。用一个堆维护即可。

代码:

/*************************************************************
    Problem: bzoj 4010 [HNOI2015]菜肴制作
    User: fengyuan
    Language: C++
    Result: Accepted
    Time: 1012 ms
    Memory: 3756 kb
    Submit_Time: 2017-12-27 17:41:50
*************************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

const int N = 100010;
int n, m, cnt, tot;
int head[N], in[N], ans[N];
struct Edge{ int to, nex; }e[N];

inline void add(int x, int y)
{
    e[++ cnt].to = y;
    e[cnt].nex = head[x];
    head[x] = cnt;
}

inline void tp()
{
    priority_queue<int> q; tot = 0;
    for(int i = 1; i <= n; i ++)
        if(!in[i]) q.push(i);
    while(!q.empty()) {
        int u = q.top(); q.pop(); ans[++ tot] = u;
        for(int i = head[u]; i; i = e[i].nex) {
            int v = e[i].to; in[v] --;
            if(!in[v]) q.push(v);
        }
    }
    if(tot != n) { puts("Impossible!"); return; }
    for(int i = tot; i >= 1; i --) printf("%d ", ans[i]); puts("");
}

int main()
{
    int Test; scanf("%d", &Test);
    while(Test --) {
        scanf("%d%d", &n, &m);
        memset(in, 0, sizeof in);
        cnt = 0; memset(head, 0, sizeof head);
        for(int i = 1; i <= m; i ++) {
            int x, y; scanf("%d%d", &x, &y);
            add(y, x); in[x] ++;
        }
        tp();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值