您的位置:首页 > 其它

bzoj2109 [Noi2010]Plane 航空管制 贪心 拓补排序

2017-11-06 17:21 281 查看
题意:定义一个航班的起 飞序号为该航班在起飞序列中的位置,即是第几个起飞的航班。 起飞序列还存在两类限制条件:  第一类(最晚起飞时间限制):编号为 i的航班起飞序号不得超过 ki;  第二类(相对起飞顺序限制):存在一些相对起飞顺序限制(a, b),表示 航班 a的起飞时间必须早于航班 b。求每个飞机在可行的起飞序列中最小的那个数。

拓补很显然,但是直接连边比较难以处理第二种限制,于是我们显然想到连反边。

考虑连反边以后,那么就可以直接做拓补序,对于每一个数,我们在topsort的时候,尽量走完他后面的点,对于x,考虑他在拓补序列中的下一个数v,如果当前时间>v的最晚限制,那么很明显不能走v,于是我们用个桶存起来,等到当前时间<=v的最早时刻(其实就是能放则放)再把他重新加入队列中。

然后假如当前要求y的答案,那么我们对于全图topsort的时候不要加入y,保证把y后面的点走完以后再加入y,至于时间限制就如上处理,最后队列为空时的时间就是y起飞的最小时间。

时间复杂度应该是O(n2logn)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
int n,m;
queue<int>q;
int head
,next
,go
,d
,dd
,lim
,tot;
int tim[2005][2005];
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
inline int topsort(int u)
{
fo(i,0,n)tim[i][0]=0;
fo(i,1,n)d[i]=dd[i];
while (!q.empty())q.pop();
fo(i,1,n)
if (!d[i]&&i!=u)
{
if (lim[i]==n)q.push(i);
else tim[lim[i]][++tim[lim[i]][0]]=i;
}
int Time=n;
while (!q.empty())
{
int x=q.front();q.pop();
for(int i=head[x];i;i=next[i])
{
int v=go[i];
d[v]--;
if (v!=u&&!d[v])
{
if (lim[v]>=Time)q.push(v);
else tim[lim[v]][++tim[lim[v]][0]]=v;
}
}
Time--;
fo(i,1,tim[Time][0])q.push(tim[Time][i]);
tim[Time][0]=0;
}
return Time;
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%d",&lim[i]),lim[i]=lim[i]>n?n:lim[i];
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
add(y,x),d[x]++;
}
fo(i,1,n)dd[i]=d[i];
fo(i,1,n)printf("%d ",topsort(i));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: