zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    .Net学习难点讨论系列2 – 细说C#中new关键字与多态
    [翻译]搜索关键字 – 管道与过滤器模式(PipesandFilters)与装饰模式(Decorator)之间的关系
    .Net学习难点讨论系列1 – 委托与事件之事件
    [翻译]Popfly系列课程1 Popfly课程计划概览
    常用桌面虚拟化软件横向对比
    各种算法的C#实现系列1 合并排序的原理及代码分析
    博客园安家
    疑:Microsoft® Silverlight™ Tools for Visual Studio 2008 SP1的版本让人困惑
    stream_socket_client
    stream_socket_client2
  • 原文地址:https://www.cnblogs.com/Narh/p/10134686.html
Copyright © 2011-2022 走看看