1. 程式人生 > >bzoj 2535 航空管制 —— 貪心+拓撲序

bzoj 2535 航空管制 —— 貪心+拓撲序

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

這個題,如果正著考慮,也就是先考慮放在前面的再考慮放在後面的,決策時會有矛盾;
也就是,如果要求 pos[a] < pos[b],則先考慮放 a,因為許多點放在 a 後面,所以 a 儘量往前放可以給它們留出空位;
但又有限制最晚起飛時間,那麼先考慮的 a 應該儘量放在靠近它最晚起飛時間的地方,以免後面的點無法滿足起飛時間的限制;
於是儘量往前放和儘量往後放形成了矛盾,無法決策;
所以需要轉化一個限制,不妨對於 pos[a] < pos[b],先決策 b;
於是兩個限制合起來的要求就都變成儘量往後放了(真神奇);


所以我們就這樣倒著做,一定能得到合法的序列;
然後考慮每個點的可能最前位置,其實就是做的過程中把這個點以及它限制的點都暫時去掉,讓其他點放好,那麼不能再放的時候就意味著只有放上這個點才能繼續,這時這個點按剛才做法找到的位置就是它的最前位置(其他點已經儘量把它的可行位置擠到前面了);
注意放點位置是最晚起飛時間和限制它的點的起飛時間取 min 的!
注意答案是起飛序列!而不是每個點的起飛位置!
如果用 set 找某位置前面第一個空位會很慢,還是並查集好。
程式碼如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include
<queue> #include<set> using namespace std; int const xn=2005,xm=10005; int n,m,hd[xn],ct,to[xm],nxt[xm],deg[xn],tmp[xn],ans[xn],d[xn],mn[xn]; struct N{ int v,id; N(int v=0,int i=0):v(v),id(i) {} }; queue<int>q; set<int>st; set<int>::iterator it; int rd() { int ret=0,f=1; char
ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;} void topo(int nw) { for(int i=1;i<=n;i++) { mn[i]=min(n,d[i]); tmp[i]=deg[i]; if(!tmp[i]&&i!=nw)q.push(i); } while(q.size()) { int x=q.front(); q.pop(); it=st.lower_bound(n-mn[x]+1); int tim=*it; //ans[x]=n-tim+1; //!!! ans[n-tim+1]=x; st.erase(tim); for(int i=hd[x],u;i;i=nxt[i]) { if((u=to[i])==nw)continue; tmp[u]--; mn[u]=min(mn[u],mn[x]);//!! if(!tmp[u])q.push(u); } } } int solve(int x) { st.clear(); for(int i=1;i<=n;i++)st.insert(i); topo(x); it=st.lower_bound(n-d[x]+1); return n-*it+1; } int main() { n=rd(); m=rd(); for(int i=1;i<=n;i++)d[i]=rd(),st.insert(i); for(int i=1,x,y;i<=m;i++)x=rd(),y=rd(),add(y,x),deg[x]++; topo(0); for(int i=1;i<=n;i++)printf("%d ",ans[i]); puts(""); for(int i=1;i<=n;i++)printf("%d ",solve(i)); puts(""); return 0; }
set
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int const xn=2005,xm=10005;
int n,m,hd[xn],ct,to[xm],nxt[xm],deg[xn],tmp[xn],ans[xn],d[xn],mn[xn];
int fa[xn],q[xn];
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return f?ret:-ret;
}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void topo(int nw)
{
  int cnt=0;
  for(int i=1;i<=n;i++)
    {
      mn[i]=min(n,d[i]); tmp[i]=deg[i]; fa[i]=i;
      if(!tmp[i]&&i!=nw)q[++cnt]=i;
    }
  while(cnt)
    {
      int x=q[cnt--]; int tim=find(mn[x]);
      ans[tim]=x; fa[tim]=tim-1;
      for(int i=hd[x],u;i;i=nxt[i])
    {
      if((u=to[i])==nw)continue;
      tmp[u]--; mn[u]=min(mn[u],mn[x]);//!!
      if(!tmp[u])q[++cnt]=u;
    }
    }
}
int solve(int x)
{
  topo(x); return find(d[x]);
}
int main()
{
  n=rd(); m=rd();
  for(int i=1;i<=n;i++)d[i]=rd();
  for(int i=1,x,y;i<=m;i++)x=rd(),y=rd(),add(y,x),deg[x]++;
  topo(0);
  for(int i=1;i<=n;i++)printf("%d ",ans[i]); puts("");
  for(int i=1;i<=n;i++)printf("%d ",solve(i)); puts("");
  return 0;
}