题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=2109
思路
很容易发现其实就是给了一个有向图,在这个有向图上做拓扑序,并限制某些点
i
必须在某个区间
网上的做法很多,但是有些做法能过BZOJ 2535却过不了2109?(这些做法的贪心策略应该是错误的),反正各种做法我都看不懂,毕竟我太弱。。。
引用vfk大爷的做法(http://vfleaking.blog.163.com/blog/static/17480763420134219155120/):可以把整个有向图反向,在反向图中,某些点
i
的拓扑序被限制最早只能在位置
那么对于第二问,我们要达到的效果就是在加入一个点之前,加入尽量多的点。对于求点
而第一问的处理也比较简单,用第二问的做法,不无视任何一个点就能得到一个合法的拓扑序了。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXE 21000
#define MAXV 2100
using namespace std;
struct edge
{
int u,v,next;
}edges[MAXE];
int head[MAXV],nCount=0;
int inDegree[MAXV],tmpdeg[MAXV];
void AddEdge(int U,int V)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].next=head[U];
head[U]=nCount;
}
struct Plane
{
int id,limit;
}plane[MAXV];
int n,m;
bool cmp(Plane a,Plane b)
{
return a.limit<b.limit;
}
int q[MAXE*2],h,t;
int limit[MAXV];
void work(int x) //在拓扑排序时不填入飞机x
{
memcpy(tmpdeg,inDegree,sizeof(inDegree));
h=t=0;
for(int i=1,p=1;i<=n;i++) //在位置i填入一个飞机
{
for(;p<=n&&plane[p].limit<i;p++)
if(!tmpdeg[plane[p].id]&&plane[p].id!=x)
q[t++]=plane[p].id;
if(h<t) //队列不为空
{
int u=q[h++]; //将u填入第i个位置
for(int p1=head[u];p1!=-1;p1=edges[p1].next)
{
int v=edges[p1].v;
tmpdeg[v]--;
if(!tmpdeg[v]&&v!=x&&limit[v]<i)
q[t++]=v;
}
}
else return;
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&plane[i].limit);
plane[i].limit=n-plane[i].limit;
plane[i].id=i;
limit[i]=plane[i].limit;
}
sort(plane+1,plane+n+1,cmp);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
inDegree[a]++;
AddEdge(b,a);
}
work(0);
for(int i=t-1;i>=0;i--)
printf("%d%c",q[i],i==0?'\n':' ');
for(int i=1;i<=n;i++)
{
work(i);
printf("%d%c",n-t,i==n?'\n':' ');
}
return 0;
}