【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("
");
  for(int i=1;i<=n;i++)
  {
    toposort(i);
    printf("%d ",n-ind[i]+1);
  }
  
  return 0;
}


原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793743.html