zoukankan      html  css  js  c++  java
  • 【BZOJ2109】【BZOJ2535】[NOI2010] 航空管制(拓扑反向建图)

    点此看题面

    大致题意:(n)个航班,每个航班有个最大起飞序号,且有若干对关系要求某航班在另一航班之前起飞。求任意一个可行的起飞序列,并求出每个航班可能的最小起飞序号。

    前言

    本以为是道三倍经验,后来发现之所以会有这两道正是因为原先的那道【BZOJ2008】[NOI2010] 航空管制它没有(SPJ)。。。

    做完这题,也算是学了一个新套路吧。感觉应该挺实用的,甚至感觉好像之前某场模拟赛遇到过这种套路的题目结果没做出来。

    然而,写个拓扑都能献上满满的(bug),我也真是醉了。。。

    反向建图

    这道题用到的是拓扑排序的一个套路:反向建图。

    考虑正向建图和反向建图配上一个优先队列有何区别。

    正向建图:求最大/最小字典序。

    反向建图:使较小/较大的数尽量靠前。

    因此,这道题显然是需要反向建图的,而这样只要随便一遍拓扑就能解决掉第一个问题。

    第二个问题

    第二个问题每次要求让某一个航班尽量靠前。

    则我们可以在反向拓扑时刚遇到这个航班时先把它拦下来(?),然后等到不得不让它走时(即队列中没有其他航班,或者队列中最大的最大起飞序号都小于当前序号)再放行。

    于是第二个问题也迎刃而解了。

    所以,事实上,只要了解了反向建图的套路,这道题就非常水了。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 2000
    #define M 10000
    #define add(x,y) (e[++ee].nxt=lnk[x],++deg[e[lnk[x]=ee].to=y])
    using namespace std;
    int n,m,a[N+5],q[N+5],ee,lnk[N+5],deg[N+5];struct edge {int to,nxt;}e[M+5];
    struct data
    {
    	int p,t;I data(CI a=0,CI b=0):p(a),t(b){}
    	I bool operator < (Con data& o) Con {return t<o.t;}
    }s[N+5];priority_queue<data> Q;
    I int Topo(CI x)//拓扑
    {
    	RI i,f=0,T=n,res;data k;for(i=1;i<=n;++i) !deg[i]&&(Q.push(s[i]),0);//初始化队列
    	W(!Q.empty()||f)
    	{
    		if(Q.empty()||Q.top().t<T) res=T,k=s[x],f=0;//不得不放行
    		else if(k=Q.top(),Q.pop(),k.p==x) {f=1;continue;}//先拦下来
    		for(i=lnk[q[T--]=k.p];i;i=e[i].nxt) !--deg[e[i].to]&&(Q.push(s[e[i].to]),0);//拓扑日常操作
    	}
    	for(i=1;i<=ee;++i) ++deg[e[i].to];return res;//把deg加回来,因为要拓扑多次
    }
    int main()
    {
    	RI i,x,y;for(scanf("%d%d",&n,&m),i=1;i<=n;++i) scanf("%d",&a[i]),s[i]=data(i,a[i]);
    	for(i=1;i<=m;++i) scanf("%d%d",&x,&y),add(y,x);//反向建图
    	for(x=Topo(1),i=1;i<=n;++i) printf("%d%c",q[i]," 
    "[i==n]);//随便搞一个合法序列,则顺便求出1的答案
    	for(printf("%d ",x),i=2;i<=n;++i) printf("%d%c",Topo(i)," 
    "[i==n]);return 0;//求出2~N的答案
    }
    
  • 相关阅读:
    ubuntu 启动 重启 停止 apache
    /usr/bin/env: php: No such file or directory 【xunsearch demo项目体验】【已解决】
    安装mezzanine时报:storing debug log for failure【已解决】
    redhat 安装 setuptools【成功】
    SnowNLP:一个处理中文文本的 Python 类库[转]
    Android 了解1G 2G 3G 知识
    Android-体系架构
    Android-bindService远程服务(Aidl)-初步
    Android-SDCard外部存储文件读写
    Android-文件模式
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2535.html
Copyright © 2011-2022 走看看