题目链接
题目解法
我们发现第二类限制明显是一个拓扑序问题
第一类限制是一个贪心,如果只考虑第二个限制的话,可以把时间从后往前扫,航班只要填一个能填的就行,这样明显是对的
考虑将二者结合,我们可以把操作都反向,将第一类限制变为 航班为 i i i 的航班起飞序号不得小于 k i k_i ki,同时建立原拓扑图的反向拓扑图
考虑第一问,只要按照之前只考虑第一类性质的贪心,在加上拓扑序都必须满足就可以了
如果要证明的话可以考虑如果一个顺序是合法的,且从后面抽一些航班到前面也是合法的,那么后面抽一些航班到前面,其他的按照原序也必定是合法的
时间复杂度
O
(
n
)
O(n)
O(n)
考虑第二问
枚举每个航班
做法与第一问相同,只要特判不能走到当前的航班即可
如果当前时间没有航班可以加了,那么这个时间就是答案
时间复杂度
O
(
n
2
)
O(n^2)
O(n2)
#include <bits/stdc++.h>
using namespace std;
const int N(2100),M(10100);
int n,m,k[N],ans[N],rudu[N];
int e[M],ne[M],h[N],idx;
vector<int> vec[N];
int wq[N],top;
bool cov1[N],cov2[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void add(int x,int y){
e[idx]=y,ne[idx]=h[x],h[x]=idx++;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++) k[i]=read(),k[i]=n-k[i]+1;
for(int i=1;i<=n;i++) vec[k[i]].push_back(i);
memset(h,-1,sizeof(h));
for(int i=1,a,b;i<=m;i++) a=read(),b=read(),add(b,a),rudu[a]++;
for(int i=1;i<=n;i++) if(!rudu[i]) cov2[i]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<vec[i].size();j++){
int x=vec[i][j];cov1[x]=1;
if(cov2[x]) wq[++top]=x;
}
ans[i]=wq[top--];
for(int j=h[ans[i]];~j;j=ne[j]){
int x=e[j];rudu[x]--;
if(!rudu[x]){
cov2[x]=1;
if(cov1[x]) wq[++top]=x;
}
}
}
for(int i=n;i;i--) printf("%d ",ans[i]);
puts("");
for(int cur=1;cur<=n;cur++){
for(int i=1;i<=n;i++) rudu[i]=cov1[i]=cov2[i]=0;
for(int i=1;i<=n;i++) for(int j=h[i];~j;j=ne[j]) rudu[e[j]]++;
for(int i=1;i<=n;i++) if(!rudu[i]&&i!=cur) cov2[i]=1;
top=0;
for(int i=1;i<=n;i++){
for(int j=0;j<vec[i].size();j++){
int x=vec[i][j];cov1[x]=1;
if(cov2[x]&&x!=cur) wq[++top]=x;
}
if(!top){ printf("%d ",n-i+1);break;}
int p=wq[top--];
for(int j=h[p];~j;j=ne[j]){
int x=e[j];rudu[x]--;
if(!rudu[x]){
cov2[x]=1;
if(cov1[x]&&x!=cur) wq[++top]=x;
}
}
}
}
return 0;
}