BZOJ 2109 航空管制(拓扑排序+贪心)
绝世好题啊。。
题意:给出一个DAG,和每个点要求出现在这个DAG里面的拓扑排序的位置<=ti,求出所有可能的拓扑排序里面每个点出现的位置的最小值。
正着做不好做,考虑反着做,建立这个图的反图。
对于一个点出现的位置的最小值,就是n-这个点在反图中出现的位置的最大值。
也就是说拓扑排序时尽量把这个点i排在后面就行了。但是还需要满足一个限制,在反图中这个限制就是每个点在拓扑排序的位置>=n-ti。
于是我们每次拓扑排序从队列中取出点的时候,尽量取n-ti值最小的点,这样就能尽量使得当前处理的点i排在尽可能后的位置。
用一个小根堆实现。因此总的时间复杂度就是O(n^2logn).
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <bitset> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi acos(-1.0) # define eps 1e-8 # define MOD 30031 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=2005; //Code begin... int dee[N], d[N], ans[N], t[N]; VI E[N]; struct qnode{ int v, c; qnode(int _v=0, int _c=0):v(_v),c(_c){} bool operator<(const qnode &r)const{return c>r.c;} }; priority_queue<qnode>Q; int main () { int n, m, u, v, num; qnode tmp; scanf("%d%d",&n,&m); FOR(i,1,n) scanf("%d",t+i), t[i]=n-t[i]; while (m--) scanf("%d%d",&u,&v), E[v].pb(u), ++dee[u]; FOR(i,1,n) { num=0; FOR(j,1,n) { d[j]=dee[j]; if (d[j]==0&&j!=i) Q.push(qnode(j,t[j])); } while (!Q.empty()) { tmp=Q.top(); Q.pop(); if (tmp.c>num) break; ++num; FO(j,0,E[tmp.v].size()) { --d[E[tmp.v][j]]; if (d[E[tmp.v][j]]==0&&E[tmp.v][j]!=i) Q.push(qnode(E[tmp.v][j],t[E[tmp.v][j]])); } } ans[i]=n-num; while (!Q.empty()) Q.pop(); } FOR(i,1,n) printf("%d ",ans[i]); putchar('\n'); return 0; }