zoukankan      html  css  js  c++  java
  • [SCOI2005]王室联邦

    https://zybuluo.com/ysner/note/1177426

    题面

    某个国王想把他的国家划分成若干个省。。。
    他的国家有(n)个城市,编号为(1...n)。一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路。为了防止管理太过分散,每个省至少要有(B)个城市,为了能有效的管理,每个省最多只有(3B)个城市。
    每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。但是该省的任意一个城市到达省会所经过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。
    一个城市可以作为多个省的省会。

    • (nleq1000)

    解析

    看完题,显然能想到一个贪心,就是进行树的(DFS),一旦发现以某个点为根的子树大小大于等于(B),则把这颗子树划为一个省。最后根节点那里一般有(x)个点未被划入省中,因(x<B),划入最后一个省(离根节点最近)即可。
    具体把子树划为省的方法是标记子树根节点,稍后再一遍(DFS)下放标记。

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    #define re register
    #define il inline
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=1200;
    int n,b,bl[N],cap[N],h[N],cnt,sz[N],top,pro[N];
    struct Edge{int to,nxt;}e[N<<1];
    il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
    il void dfs(re int u,re int fa)
    {
      sz[u]=1;
      for(re int i=h[u];i+1;i=e[i].nxt)
        {
          re int v=e[i].to;
          if(v==fa) continue;
          dfs(v,u);
          sz[u]+=sz[v];
        }
      if(sz[u]>b) bl[u]=++top,cap[top]=u,sz[u]=0;
    }
    il void lab(re int u,re int fa,re int id)
    {
      if(!bl[u]) bl[u]=id,pro[id]++;else id=bl[u],pro[bl[u]]++;
      if(!cap[id]) cap[id]=u;
      for(re int i=h[u];i+1;i=e[i].nxt)
        {
          re int v=e[i].to;
          if(v==fa) continue;
          lab(v,u,id);
        }
    }
    int main()
    {
      memset(h,-1,sizeof(h));
      n=gi();b=gi();
      fp(i,1,n-1)
        {
          re int u=gi(),v=gi();
          add(u,v);add(v,u);
        }
      dfs(1,0);
      lab(1,0,top);
      printf("%d
    ",top);
      fp(i,1,n) printf("%d ",bl[i]);puts("");
      fp(i,1,top) printf("%d ",cap[i]);puts("");
      return 0;
    }
    

    但这样只能获得(90pts)
    因为这么弄就排除了一个城市为多省省会省会在该省省外的情况。
    这种情况表明一个省份是可以不联通的,即一个节点有两个子节点,两个子节点属于一个省,根节点属于另一个省。
    造数据就是一个根节点,它的所有子节点子树大小都不到(B),但它自己子树大小超过(3B)
    维护这类省份就只能用栈了。注意搜到一节点时最后再把该节点加入栈。

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    #define re register
    #define il inline
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=1200;
    int n,b,bl[N],cap[N],h[N],cnt,sta[N],tot,top;
    struct Edge{int to,nxt;}e[N<<1];
    il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
    il void dfs(re int u,re int fa)
    {
      re int now=tot;
      for(re int i=h[u];i+1;i=e[i].nxt)
        {
          re int v=e[i].to;
          if(v==fa) continue;
          dfs(v,u);
          if(tot-now>=b) {cap[++top]=u;while(tot^now) bl[sta[tot--]]=top;}
        }
      sta[++tot]=u;
    }
    int main()
    {
      memset(h,-1,sizeof(h));
      n=gi();b=gi();
      fp(i,1,n-1)
        {
          re int u=gi(),v=gi();
          add(u,v);add(v,u);
        }
      dfs(1,0);
      while(tot) bl[sta[tot--]]=top;
      printf("%d
    ",top);
      fp(i,1,n) printf("%d ",bl[i]);puts("");
      fp(i,1,top) printf("%d ",cap[i]);puts("");
      return 0;
    }
    
  • 相关阅读:
    福大软工1816 · 第五次作业
    团队编程
    结队第一次作业
    词频统计 ——Java
    Alpha 冲刺 (3/10)
    Alpha 冲刺 (2/10)
    Alpha 冲刺 (1/10)
    2018软工实践第七次作业——需求报告分析
    福大软工 · 第八次作业(课堂实战)- 项目UML设计(团队)
    2018软工实践第六次作业——团队选题报告
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9162682.html
Copyright © 2011-2022 走看看