1. 程式人生 > >bzoj 2535 && bzoj 2109 [Noi2010]Plane 航空管制——貪心

bzoj 2535 && bzoj 2109 [Noi2010]Plane 航空管制——貪心

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=2535

   https://www.lydsy.com/JudgeOnline/problem.php?id=2109

考慮按拓撲序決策,發現不太行;主要是一種情況:雖然自己的 k[ ] 靠後,但自己限制的點的 k[ ] 靠前。

這樣的話,自己應該儘量往前放;但為了別的點的這種情況,自己又應該儘量往後放,所以無法決策了。

發現這種情況主要和後面的點是否緊急有關。所以就是雖然拓撲序是那樣的,但可以先決策的點應該是拓撲序靠後的點。

所以反著拓撲,然後按順序決策。那麼一個點就是在符合自己 k[ ] 的基礎上儘量往後放就行了。

  這裡能放的位置應該是自己 k[ ] 之前的第一個沒被佔用的位置,可以用並查集而不是 set (只是會變慢罷了)維護。

考慮第二問,則儘量先把其他點往後放,非放自己不可的時候再放自己,那麼自己就被放在自己能放的最前面了。

  方法就是先決策其他點,遇到自己可以決策也不決策。最後非放自己不可的時候其他沒放的點一定都是被自己限制的點,則自己只能放在當前空位的最後一個。

注意找自己的 k[ ] 之前的第一個沒被佔用的位置的時候應該考慮一下自己應該放在限制自己的那些點的前面!

  比如一個點限制要放在另一個點前面,但它的 k[ ] 卻比那個點大;直接按剛才說的找位置的話自己可能放在限制自己點的後面了。

  要解決這種情況,只要拓撲的時候 k[ v ] 對 k[ cr ] 取 min 就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
using namespace std;
const int N=2005,M=10005;
int n,m,hd[N],xnt,to[M],nxt[M],fa[N],sta[N],top;
int deg[N],ydeg[N],r[N],ans[N];
queue<int
> q; int rdn() { int ret=0;bool fx=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } int Mn(int a,int b){return a<b?a:b;} void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;deg[y]++;} int fnd(int a){return fa[a]==a?a:fa[a]=fnd(fa[a]);} void solve(int cr) { memcpy(deg,ydeg,sizeof ydeg); for(int i=1;i<=n;i++)fa[i]=i; top=0; for(int i=1;i<=n;i++)if(!deg[i]&&i!=cr)sta[++top]=i; while(top) { int k=sta[top--],d=fnd(r[k]); fa[d]=fnd(d-1); for(int i=hd[k],v;i;i=nxt[i]) if(!(--deg[v=to[i]])&&v!=cr)sta[++top]=v; } printf("%d ",fnd(n)); } int main() { n=rdn();m=rdn(); for(int i=1;i<=n;i++)r[i]=rdn(); for(int i=1,u,v;i<=m;i++) { u=rdn();v=rdn();add(v,u); } memcpy(ydeg,deg,sizeof deg); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=n;i++)if(!deg[i])sta[++top]=i; int deb=0; while(top) { int k=sta[top--],d=fnd(r[k]); ans[d]=k;fa[d]=fnd(d-1); for(int i=hd[k],v;i;i=nxt[i]) { r[v=to[i]]=Mn(r[v],r[k]);// if(!(--deg[v]))sta[++top]=v; } } for(int i=1;i<=n;i++)printf("%d ",ans[i]);puts(""); for(int i=1;i<=n;i++)solve(i);puts(""); return 0; }