【NOI2010T4】航空管制-拓补排序+贪心
测试地址:航空管制
做法:考虑存储原图的反图,然后进行加了一些限制的拓补排序,这个图的拓补序的反序就是第一问的答案。然后考虑第二问,我们可以贪心来做,我们先不管当前的航班,对其他航班进行拓补排序,当队列中没有办法再插入元素的时候,就是当前航班插入的时候了,这样得到的拓补序的反序中当前航班就是在它可行的最早位置了。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int n,m,first[4010]={0},in[4010]={0},din[4010],d[4010],ind[4010],t,tot=0;
struct {int v,next;} e[40010];
void insert(int a,int b)
{
e[++tot].v=b,e[tot].next=first[a],first[a]=tot;
}
void toposort(int avoid)
{
memset(ind,0,sizeof(ind));
t=0;
queue<int> q;
for(int i=1;i<=2*n+1;i++) din[i]=in[i];
for(int i=1;i<=2*n+1;i++)
if (!din[i]&&i!=avoid)
{
q.push(i);
if (i<=n) ind[i]=++t;
}
while(!q.empty())
{
int v=q.front();q.pop();
if (v==avoid)
{
if (q.empty()) break;
else {q.push(v);continue;}
}
for(int i=first[v];i;i=e[i].next)
{
din[e[i].v]--;
if (!din[e[i].v]&&e[i].v!=avoid)
{
if (e[i].v<=n||e[i].v-n>=n-t+1) q.push(e[i].v);
if (e[i].v<=n) ind[e[i].v]=++t;
}
}
}
ind[avoid]=++t;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=n+1;i>=2;i--)
{
insert(n+i,n+i-1);
in[n+i-1]++;
}
for(int i=1,k;i<=n;i++)
{
scanf("%d",&k);
insert(n+k+1,i);
in[i]++;
}
for(int i=1,a,b;i<=m;i++)
{
scanf("%d%d",&a,&b);
insert(b,a);
in[a]++;
}
toposort(0);
for(int i=1;i<=n;i++)
d[n-ind[i]+1]=i;
for(int i=1;i<=n;i++) printf("%d ",d[i]);
printf("\n");
for(int i=1;i<=n;i++)
{
toposort(i);
printf("%d ",n-ind[i]+1);
}
return 0;
}