• BZOJ5280: [Usaco2018 Open]Milking Order(二分+拓扑)


    5280: [Usaco2018 Open]Milking Order

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 123  Solved: 62
    [Submit][Status][Discuss]

    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,第一种是字典序较小的。

    HINT

    Source

    思路:一眼题,由于不方便按照顺序加边,然后每次判断是否有环。 由于是最大的前缀边,我们按边数二分然后判断,然后可以tarjan判断环,但是也可以直接拓扑判断同时得到答案,就懒得写tarjan了,因为如果有环,环里的点是拓扑不出来的,最后判断如果没有拓扑完所有的点,说明有环,否则更新答案。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define pb push_back
    using namespace std;
    const int maxn=400010;
    vector<int>G[maxn]; int res[maxn],ans[maxn],N,M;
    int Laxt[maxn],Next[maxn],To[maxn],ind[maxn],cnt,tot;
    void add(int u,int v){
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; ind[v]++;
    }
    bool check(int Mid)
    {
        rep(i,1,N) Laxt[i]=0,ind[i]=0;
        priority_queue<int,vector<int>,greater<int> >q; cnt=0; tot=0;
        rep(i,1,Mid){
            rep(j,1,G[i].size()-1) add(G[i][j-1],G[i][j]);
        }
        rep(i,1,N) if(!ind[i]) q.push(i);
        while(!q.empty()){
            int u=q.top(); ans[++tot]=u;
            q.pop();
            for(int i=Laxt[u];i;i=Next[i]){
                int v=To[i]; ind[v]--;
                if(!ind[v]) q.push(v);
            }
        }
        return tot==N;
    }
    int main()
    {
        scanf("%d%d",&N,&M);
        rep(i,1,M){
            int num,x; scanf("%d",&num);
            rep(j,1,num) scanf("%d",&x),G[i].pb(x);
        }
        int L=1,R=M,Mid;
        while(L<=R){
            Mid=(L+R)>>1;
            if(check(Mid)) {
                L=Mid+1;
                rep(i,1,N) res[i]=ans[i];
            }
            else R=Mid-1;
        }
        rep(i,1,N) printf("%d ",res[i]);
        return 0;
    }
  • 相关阅读:
    一篇文章看懂mysql中varchar能存多少汉字、数字,以及varchar(100)和varchar(10)的区别
    SQL处理下划线分割的两边数字都分别增加值
    [LeetCode]Binary Tree Zigzag Level Order Traversal
    [LeetCode]Binary Tree Level Order Traversal
    [LeetCode]Candy
    [LeetCode]Single Number II
    [LeetCode]Single Number
    [LeetCode]Copy List with Random Pointer
    [LeetCode]Link List Cycle II
    [LeetCode]Link List Cycle
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9957135.html
Copyright © 2020-2023  润新知