zoukankan      html  css  js  c++  java
  • [bzoj4010][HNOI2015]菜肴制作_贪心_拓扑排序

    菜肴制作 bzoj-4010 HNOI-2015

    题目大意:给定一张n个点m条边的有向图,求一个toposort,使得:(1)满足编号为1的点尽量在前;(2)满足(1)的情况下编号为2的点尽量在前,以此类推。

    注释:$1le n,mle 10^5$,$1le cases le 3$。


    想法:只需要先求字典序最大toposort,然后逆序输出即可。

    简单的证明:字典序最大的toposort是将当前所有解锁的中编号最大的点放在首位,这样1就会自然而然排在最后。自然就会满足所有的条件。

    更严格地,我们采用数学归纳法。

    奠基:如上文,我们将可能放在1前面的都放在了1前面,逆序输出的话就会使得1的位置是可能情况下最靠前的,即满足(1)。

    归纳假设:若前i个条件都会且仅会在最大拓扑序逆序的条件下被满足,那么对于第i+1点,在前i个点都满足题意的时候,当前解锁的点中如果没有i+1,不考虑。

    如果有i+1:

    当这些点中还有比i+1更小的点,由归纳假设,想满足前i个条件,只能先放比i大的点,所以比i+1小的点我们不理它们。

    那么只考虑不小于i+1的点,我们期望满足条件(i+1)。

    所以我们将所有比i+1大的点都先放出来,这样会最大限度地使i+1靠前。

    直到当前解锁的点中i+1为最大者,我们才将它放出来。

    这样的话,因为满足前i个条件的话我们不能解锁小于i+1的点。在这样的情况下我们又将所有可能放在i+1后面的点放在了i+1后面,所以i+1是在满足前i个条件下最靠前的。

    这样我们就满足了条件(i+1)。

    证毕

    最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define N 100010 
    using namespace std;
    priority_queue<int>q;
    int to[N],nxt[N],head[N],tot;
    bool vis[N]; int num[N],cnt,ans[N],n,m;
    inline void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
    }
    inline void original()
    {
        tot=cnt=0;
        memset(head,0,sizeof head);
        memset(num,0,sizeof num);
        memset(vis,false,sizeof vis);
        while(!q.empty()) q.pop();
    }
    bool flag;
    void toposort()
    {
        while(!q.empty())
        {
            int x=q.top(); q.pop();
            ans[++cnt]=x;
            vis[x]=true;
            for(int i=head[x];i;i=nxt[i])
            {
                num[to[i]]--;
                if(!num[to[i]]) q.push(to[i]);
            }
        }
        for(int i=1;i<=n;i++) if(!vis[i]) {flag=false; return; }
    }
    int main()
    {
        int cases; cin >> cases ;
        while(cases--)
        {
            original();
            cin >> n >> m ;
            for(int x,y,i=1;i<=m;i++) scanf("%d%d",&x,&y),add(y,x),num[x]++;
            flag=true;
            for(int i=1;i<=n;i++)
            {
                if(num[i]) continue;
                q.push(i);
            }
            toposort();
            if(flag) for(int i=cnt;i>=1;i--) printf("%d ",ans[i]);
            else printf("Impossible! ");
            puts("");
        }
    }
    /*
    3 
    5 4 
    5 4 
    5 3 
    4 2 
    3 2 
    3 3 
    1 2 
    2 3 
    3 1 
    5 2 
    5 2 
    4 3 
    */
    

    小结大胆假设,小心求证

  • 相关阅读:
    leetcode Convert Sorted List to Binary Search Tree
    leetcode Convert Sorted Array to Binary Search Tree
    leetcode Binary Tree Level Order Traversal II
    leetcode Construct Binary Tree from Preorder and Inorder Traversal
    leetcode[105] Construct Binary Tree from Inorder and Postorder Traversal
    证明中序遍历O(n)
    leetcode Maximum Depth of Binary Tree
    限制 button 在 3 秒内不可重复点击
    HTML 和 CSS 画三角形和画多边行基本原理及实践
    在线前端 JS 或 HTML 或 CSS 编写 Demo 处 JSbin 与 jsFiddle 比较
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9397611.html
Copyright © 2011-2022 走看看