zoukankan      html  css  js  c++  java
  • [BZOJ5280] [Usaco2018 Open]Milking Order

    Description

    Farmer John的N头奶牛(1≤N≤105),仍然编号为1…N,正好闲得发慌。因此,她们发展了一个与Farmer John每
    天早上为她们挤牛奶的时候的排队顺序相关的复杂的社会阶层。经过若干周的研究,Farmer John对他的奶牛的社
    会结构总计进行了M次观察(1≤M≤50,000)。每个观察结果都是他的某些奶牛的一个有序序列,表示这些奶牛应
    该以与她们在序列中出现的顺序相同的顺序进行挤奶。比方说,如果Farmer John的一次观察结果是序列2、5、1,
    Farmer John应该在给奶牛5挤奶之前的某个时刻给奶牛2挤奶,在给奶牛1挤奶之前的某个时刻给奶牛5挤奶。Farme
    r John的观察结果是按优先级排列的,所以他的目标是最大化X的值,使得他的挤奶顺序能够符合前X个观察结果描
    述的状态。当多种挤奶顺序都能符合前X个状态时,Farmer John相信一个长期以来的传统——编号较小的奶牛的地
    位高于编号较大的奶牛,所以他会最先给编号最小的奶牛挤奶。更加正式地说,如果有多个挤奶顺序符合这些状态
    ,Farmer John会采用字典序最小的那一个。挤奶顺序x的字典序比挤奶顺序y要小,如果对于某个j,xi=yi对所有i
    <j成立,并且xj<yj(也就是说,这两个挤奶顺序到某个位置之前都是完全相同的,在这个位置上x比y要小)。请
    帮助Farmer John求出为奶牛挤奶的最佳顺序。

    Input

    第一行包含N和M。
    接下来的M行,每行描述了一个观察结果。
    第i+1行描述了观察结果i,第一个数是观察结果中的奶牛数量mi,后面是一列mi个整数,给出这次观察中奶牛的顺序。
    所有mi的和至多为200,000

    Output

    输出N个空格分隔的整数,给出一个1…N的排列,为Farmer John给他的奶牛们挤奶应该采用的的顺序。
     

    Sample Input

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

    Sample Output

    1 4 2 3

    这里,Farmer John有四头奶牛,他的挤奶顺序应该是奶牛1在奶牛2之前、奶牛2在奶牛3之前(第一个观察结果)
    ,奶牛4在奶牛2之前(第二个观察结果),奶牛3在奶牛4之前、奶牛4在奶牛1之前(第三个观察结果)。前两个观
    察结果可以同时被满足,但是Farmer John不能同时满足所有的规则,因为这样的话会要求奶牛1在奶牛3之前,同
    时奶牛3在奶牛1之前。这意味着总共有两种可能的挤奶顺序:1 4 2 3和4 1 2 3,第一种是字典序较小的。
     

     
    挺显然的套路题吧。
    一看这个题就知道二分答案...
    二分最后一个可以满足的位置,然后我们要判断是否可行。
    然后看题目显然的先后关系,关系明了且层次鲜明, 一看就是拓扑排序的样子。
    于是我们对关系$s1 < s2$, 我们把$s1$向$s2$连有向边,然后跑拓扑看看是否有环。
    我们二分出了最后一个可以满足的位置,下一个问题就是如何找出来字典序最小的方案。
    经过简单的思考,自然而然的想到,把拓扑排序的队列强行换成优先队列...
    这样稳A?
    这在$Bzoj$上A了,但在$Luogu$上$T$了!!!活久见!!
    所以我代码其实可以修改的地方挺多的, 比如可以把算答案的函数和判断是否合法的函数分开,判断是否合法只用普通队列,算答案再用优先队列,也少去了不少if语句。
    这样优化预计跑得很快...
    毕竟最高复杂度才$large O(NlogN)$。
    我写萎的貌似是$large O(Nlog^2N)$的。
     

     
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    #include <vector>
    using namespace std;
    #define reg register
    inline int read() {
        int res=0;char ch=getchar();bool fu=0;
        while(!isdigit(ch)){if(ch=='-')fu=1;ch=getchar();}
        while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
        return fu?-res:res;
    }
    
    int n, m;
    int s[50005];
    vector <int> T[50005];
    int deg[100005];
    struct edge {
        int nxt, to;
    }ed[200005];
    int head[100005], cnt;
    inline void add(int x, int y) {
        ed[++cnt] = (edge){head[x], y};
        head[x] = cnt;
        deg[y]++;
    }
    int rod[100005], Top;
    inline bool Topsort(bool fl)
    {
        priority_queue <int, vector <int>, greater<int> > q;
        for (reg int i = 1 ; i <= n ; ++ i) 
            if (deg[i] == 0) q.push(i);
        while(!q.empty())
        {
            int x = q.top();q.pop();
            if (fl) rod[++Top] = x;
            for (reg int i = head[x] ; i ; i = ed[i].nxt)
            {
                int to = ed[i].to;
                deg[to]--;
                if (!deg[to]) q.push(to);
            }
        }
        for (reg int i = 1 ; i <= n ; ++ i)
            if (deg[i]) return 0;
        return 1;
    }
    
    inline bool check(int mid, bool fl)
    {
        cnt = 0;
        memset(head, 0, sizeof head);
        memset(deg, 0, sizeof deg);
        for (reg int i = 1 ; i <= mid ; ++ i)
        {
            for (reg int j = 0 ; j < T[i].size() - 1 ; ++ j)
            {
                int x = T[i][j], y = T[i][j+1];
                add(x, y);
            }
        }
        if (fl) return Topsort(1);
        
        return Topsort(0);
    }
    
    int main()
    {
        n = read(), m = read();
        for (reg int i = 1 ; i <= m ; ++ i)
        {
            s[i] = read();
            for (reg int j = 1 ; j <= s[i] ; ++ j)
                T[i].push_back(read());
        }
        int l = 1, r = m, ans = 1;
        while(l <= r) 
        {
            int mid = l + r >> 1;
            if (check(mid, 0)) ans = mid, l = mid + 1;
            else r = mid - 1;
        }
        check(ans, 1);
        for (reg int i = 1 ; i <= n ; ++ i) printf("%d ", rod[i]);
        return 0;
    }
  • 相关阅读:
    UVA 10066 The Twin Towers
    UVA 10192 Vacation
    hdu 5018 Revenge of Fibonacci
    hdu 5108 Alexandra and Prime Numbers
    UVA 10252
    UVA 10405最长公共子序列
    数塔
    hdu 2602
    面向对象(五)
    面向对象(三)
  • 原文地址:https://www.cnblogs.com/BriMon/p/9657222.html
Copyright © 2011-2022 走看看