zoukankan      html  css  js  c++  java
  • 暑期集训20190729 字典序(dictionary)

    【题目描述】 你需要构造一个1~n的排列,使得它满足m个条件,每个条件形如(ai,bi),表示ai必须在bi前面。 在此基础上,你需要让1尽可能靠前,然后你需要让2尽可能靠前,然后是3,4,5,…,n。

    【输入数据】 第一行两个正整数n,m。接下来m行每行两个数ai,bi。

    【输出数据】 输出一行n个整数表示答案。如果不存在这样的排列,输出-1。

    【样例输入】 5 4 5 4 5 3 4 2 3 2

    【样例输出】 1 5 3 4 2

    【数据范围】 对于20%的数据,n,m<=10。 对于40%的数据,n,m<=200。 对于60%的数据,n,m<=1000。 对于100%的数据,n,m<=100000。

    对于每组条件连一条有向边, 然后对形成的图进行拓扑排序,

    每次拿出的点放入大根堆中,依序输出并删边,最后将所有输出结果反序。

    (第一次做理解成了“字典序最小”,就拿了二十分……)

    原理上:倒着建图,用堆求出一个字典序最大的拓扑序,反过来输出即可。

    正确性可以用反证法证明。

    #include <bits/stdc++.h>
    using namespace std;
    
    priority_queue<int> q;
    vector<int> v[100010];
    
    int c[100010], ans[100010];
    int n, m;
    int ecnt=0, acnt=0;
    
    void dlt(int num){
        ans[acnt++] = num;
        for(int i=0; i<v[num].size(); i++){
            if(c[v[num][i]] == 1) q.push(v[num][i]);
            c[v[num][i]]--;    
        }
    }
    int main(){
        freopen("dictionary.in", "r", stdin);
        freopen("dictionary.out", "w", stdout);
        scanf("%d%d", &n, &m);
    
        for(int i=0; i<m; i++){
            int t1, t2;
            scanf("%d%d", &t1, &t2);
            v[t2].push_back(t1);
            c[t1]++;
        }
        for(int i=1; i<=n; i++){
            if(c[i] == 0){
                q.push(i);
            }
        }    
        while(true){
            if(q.empty()) break;
            int temp = q.top();
            q.pop();
            dlt(temp);
        }
        if(acnt==n){
            for(int i=n-1; i>=0; i--)
                printf("%d ", ans[i]);
        }
        else printf("-1");
        return 0;
    }
  • 相关阅读:
    动态水母
    jquery封装的方法
    近千部最新英文读物(word 格式)及下载阅读方法
    best tanks
    System Analysic utility tools
    高级商务英语(BEC)阅读题应试指南
    “牛”人是怎样学习的
    领悟
    BEC高级商务英语考试应试技巧指南
    因特网上的英语学习资源
  • 原文地址:https://www.cnblogs.com/miserweyte/p/11270675.html
Copyright © 2011-2022 走看看