您的位置:首页 > 其它

2008/2109/2535: [Noi2010]航空管制

2017-07-17 19:41 260 查看
题目链接

题目大意:一个有向图,在这个有向图上做拓扑序,并限制某些点i的位置必须在区间[1,ki]中,第一问求合法序列,第二问求每个点在拓扑序中最早在什么位置出现。

题解:本来是三倍经验,但是2008没有special judge过不了,只有双倍了23333

考虑第二问:考虑到一下求出全部的答案不太好搞,分开一个个考虑。若直接贪心的话,没法确定先加入哪个入度为0的点(因为有后效性)。把有向图反向,问题就变成了求点最晚的出现位置,没有后效性了

在求点i的答案时,做拓扑序限制点i,剩下的点按限制时间排序,然后一直加入限制时间允许且入度为0的点,直到没法加为止,这时就是i的最晚时间,因为所有能加入的都加入了

对于第一问,可以当作不限制任何点

我的收获:……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define f first
#define s second
#define M 2005

int n,m,k,t;
int head[M],q[M*10],in[M],r[M],limit[M];

pair <int,int> pla[M];

struct edge{int to,nex;}e[M*10];

void add(int u,int v){e[t].to=v,e[t].nex=head[u],head[u]=t++;}

int toposort(int x){
int h=0,w=0;
memcpy(r,in,sizeof(in));
for(int i=1,p=1;i<=n;i++) {
for (;p<=n&&pla[p].f<i;p++)
if (!r[pla[p].s]&&pla[p].s!=x)
q[++w]=pla[p].s;
if(h<w){
int u=q[++h];
for(int j=head[u];j!=-1;j=e[j].nex){
int v=e[j].to;r[v]--;
if(!r[v]&&v!=x&&limit[v]<i)
q[++w]=v;
}
}
else return w;
}
return w;
}

void work()
{
int tm=toposort(0);
for(int i=tm;i>=1;i--)
printf("%d%c",q[i],i>1?' ':'\n');
for(int i=1;i<=n;i++)
printf("%d%c",n-toposort(i),i<n?' ':'\n');
}

void init()
{
int x,y;t=0;memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&pla[i].f),pla[i].f=n-pla[i].f,pla[i].s=i,limit[i]=pla[i].f;
for(int i=1;i<=m;i++) scanf("%d%d",&x,&y),add(y,x),in[x]++;
sort(pla+1,pla+1+n);
}

int main()
{
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: