• 【拓扑排序】BZOJ4010-[HNOI2015]菜肴制作


    【题目大意】

    是要求N个点的一个拓扑序,且满足以下条件:编号1的位置尽可能靠前,在满足所有限制,编号2的位置尽可能靠前,以此类推。

    【思路】

    一开始觉得优先队列维护一下拓扑就好了。然而样例告诉我们是不可以的。如果限制条件是:
    5 2
    4 3

    最后出来的会是1-4-3-5-2,而答案应该是1-5-2-4-3。

    由此可以发现,如果正向拓扑出来的是“字典序最小”,而不是“编号小的尽可能靠前”。

    所以逆向拓扑。

    证明……算了困了,改天再纠结吧。丢个链接存个档。

    不妨认为我们这样得到的不是最优解,那么令这样得到的序列为a,然后最优解是b。
    我们从后往前开始找到第一位两个序列不同的一位设为k,那么a[k]!=b[k],且a[k]>b[k]。(由a的构造方式可知)(先假设这个k存在,再证出矛盾)
    再设a[k]出现的b的p位置,即b[p]=a[k]。再设b[p] b[p+1]……b[k]这个子序列为C。
    那么b[p]一定不是C中的最小元素,因为有b[k]<b[p]=a[k]。
    然后不妨设b[q]为C的最小元素。然后我们把b[p]移到b[k]的位置,得到序列bb。
    如果bb合法的话,那么我们就得到了一个比b优的解,这与b是最优解矛盾。
    (因为b[q]的位置前移了一位,我们要求编号小的尽可能靠前)
    但bb显然是合法的。因为在a序列中k以及后面的是合法的,那么b后面也这么做一定也是合法的。
    所以一定不存在某个k,使得a[k]!=b[k]。也就是说a=b。
    所以算法正确性得证。
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int MAXN=100000+50;
     4 int n,m,in;
     5 vector<int> E[MAXN];
     6 priority_queue<int> que;
     7 int ans[MAXN],inn[MAXN];
     8 
     9 void init()
    10 {
    11     scanf("%d%d",&n,&m);
    12     memset(inn,0,sizeof(inn));
    13     for (int i=1;i<=n;i++) vector<int>().swap(E[i]);
    14     for (int i=0;i<m;i++)
    15     {
    16         int u,v;
    17         scanf("%d%d",&u,&v);
    18         inn[u]++;
    19         E[v].push_back(u);
    20     }
    21 }
    22 
    23 void solve()
    24 {
    25     while (!que.empty()) que.pop();
    26     ans[0]=0;
    27     for (int i=1;i<=n;i++) if (!inn[i]) que.push(i);
    28     while (!que.empty())
    29     {
    30         int u=que.top();que.pop();
    31         ans[++ans[0]]=u;
    32         for (int i=0;i<E[u].size();i++)
    33         {
    34             int v=E[u][i];
    35             inn[v]--;
    36             if (!inn[v]) que.push(v);
    37         }
    38     }
    39     if (ans[0]<n) puts("Impossible!");
    40         else 
    41         {
    42             for (int i=ans[0];i>=1;i--) printf("%d ",ans[i]);
    43             printf("
    ");
    44         }
    45 }
    46 
    47 int main()
    48 {
    49     int T;
    50     scanf("%d",&T);
    51     while (T--)
    52     {
    53         init();
    54         solve();
    55     }
    56     return 0;
    57 }
  • 相关阅读:
    Shell判断文件或目录是否存在
    linux使用wpa_supplicant手动配置wifi
    ubuntu更换apt源后依然搜索旧软件源下载失败问题
    在Ubuntu下解决E: 无法对目录 /var/lib/apt/lists/ 加锁的问题
    Bash中判断一个命令的输出结果是否为空
    [解决]/bin/bash^M: bad interpreter: No such file or directory
    【转】 使用 NetworkManager 命令行工具 nmcli
    【转】wpa_supplicant及wpa_cli使用方法
    [RK3288] Vendor Storage区域知识及探讨
    安装oracle 时“[INS-30014]无法检查指定的位置是否位于 CFS上”问题
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/6072043.html
Copyright © 2020-2023  润新知