zoukankan      html  css  js  c++  java
  • BZOJ2535: [Noi2010]Plane 航空管制2

    正解有点巧妙没想出来。学到了,以后这种题,最早呀,最晚呀,拓扑呀,可以往反图方面想想。

    参考这位大佬的 https://blog.csdn.net/weixin_34377065/article/details/86020916

    应该不少人一开始想的是正着做,弄个优先队列优先让时限早的先飞。这样听起来很对,其实是错的,上面博客有一句话说得很好:因为当前的k小并不意味着后面的点k也小

    这里给出一个正着做的错误:3->5  4->2  这里的数字代表时限,箭头代表连边。合法情况应该是4->2->3->5。但是因为优先队列优先时限小的会变成3->4->2->5显然是错误的。因为当前小不代表后面小,当前大也不代表后面大。

    那为什么倒着做是正确的呢?因为题目本身给的时限的意思就是最晚飞行时间,那么我们倒着做就是让后面时限大的飞机尽量晚飞,题目保证有解那么肯定不会出现  时限最大的飞机最晚飞  然后无解这种情况。

    这是卡着时限飞的意思,能拖就拖。

    那么第二问的最早飞行时间,我们枚举飞机i,意思就是飞机i最早只能在这个时间飞,再早了就会影响别人。那么在反图上就是,强制让飞机i不飞(因为在反图的缘故,拖着不飞就是尽量早飞),直到它影响了别人的时刻,这就是它的最早飞行时刻,因为再早了就影响别人了。

    这道题还是非常有意思的,值得多多思考。

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int> pii;
    const int N=1e4+10;
    int n,m,deg[N],k[N],p[N],rc[N];
    vector<int> G[N];
    
    priority_queue<pii> q;
    void toposort() {
        int cnt=0;
        for (int i=1;i<=n;i++) 
            if (deg[i]==0) q.push(make_pair(k[i],i));
        while (!q.empty()) {
            pii x=q.top(); q.pop();
            p[++cnt]=x.second;
            for (int i=0;i<G[x.second].size();i++) {
                int y=G[x.second][i];
                if (--deg[y]==0) q.push(make_pair(k[y],y));
            }
        }
        for (int i=cnt;i>=1;i--) printf("%d ",p[i]); puts("");
    }
    
    int solve(int t) {
        while (!q.empty()) q.pop();
        for (int i=1;i<=n;i++) deg[i]=rc[i];
        deg[t]=0x3f3f3f3f;  //把t点度数设为无穷大,无法入队 
        for (int i=1;i<=n;i++)
            if (deg[i]==0) q.push(make_pair(k[i],i));
        for (int i=n;i;i--) {
            if (q.empty()) return i;
            pii x=q.top(); q.pop();
            if (x.first<i) return i;
            for (int i=0;i<G[x.second].size();i++) {
                int y=G[x.second][i];
                if (--deg[y]==0) q.push(make_pair(k[y],y));
            }
        }
        return n;
    }
    
    int main()
    {
        cin>>n>>m;
        for (int i=1;i<=n;i++) scanf("%d",&k[i]);
        for (int i=1;i<=m;i++) {
            int x,y; scanf("%d%d",&x,&y); 
            G[y].push_back(x); deg[x]++;
        }
        memcpy(rc,deg,sizeof(deg));
        toposort();
    
        for (int i=1;i<=n;i++) printf("%d ",solve(i));
        return 0;
    }
  • 相关阅读:
    windows应用程序单实例
    11. 无数人难办事?
    递归、尾递归和使用Stream延迟计算优化尾递归
    吴裕雄--天生自然MySQL学习笔记:MySQL 函数
    吴裕雄--天生自然MySQL学习笔记:MySQL 导入数据
    吴裕雄--天生自然MySQL学习笔记:MySQL 导出数据
    吴裕雄--天生自然MySQL学习笔记:MySQL 及 SQL 注入
    吴裕雄--天生自然MySQL学习笔记:MySQL 处理重复数据
    吴裕雄--天生自然MySQL学习笔记:MySQL 序列使用
    吴裕雄--天生自然MySQL学习笔记:MySQL 元数据
  • 原文地址:https://www.cnblogs.com/clno1/p/10828260.html
Copyright © 2011-2022 走看看