zoukankan      html  css  js  c++  java
  • luogu P2018 消息传递

    P2018 消息传递

    2017-09-13


    题目描述

    巴蜀国的社会等级森严,除了国王之外,每个人均有且只有一个直接上级,当然国王没有上级。如果A是B的上级,B是C的上级,那么A就是C的上级。绝对不会出现这样的关系:A是B的上级,B也是A的上级。

    最开始的时刻是0,你要做的就是用1单位的时间把一个消息告诉某一个人,让他们自行散布消息。在任意一个时间单位中,任何一个已经接到消息的人,都可以把消息告诉他的一个直接上级或者直接下属。

    现在,你想知道:

    1.到底需要多长时间,消息才能传遍整个巴蜀国的所有人?

    2.要使消息在传递过程中消耗的时间最短,可供选择的人有那些?


    输入输出格式

    输入格式:

    输入文件的第一行为一个整数N(N≤1000),表示巴蜀国人的总数,假如人按照1到n编上了号码,国王的编号是1。第2行到第N行(共N-1行),每一行一个整数,第i行的整数表示编号为i的人直接上级的编号。

    输出格式:

    文件输出共计两行:

    第一行为一个整数,表示最后一个人接到消息的最早时间。

    第二行有若干个数,表示可供选择人的编号,按照编号从小到大的顺序输出,中间用空格分开。


    输入输出样例

    输入样例#1:
    8
    1
    1
    3
    4
    4
    4
    3
    输出样例#1:
    5
    3 4 5 6 7


    原本一看这个题,暴力找重心,然后跑树,然后经过仔细读题,发现并没有用到重心,我们只要找到一个点到树的最长的一条带边权的路径和最大的最小。
    f每一个点上的边权是从1到所连边个数的全排列,(因为每一次只能传一个)所以我们贪心选取使边权的大值对应它所连点底下边权和较小的值.
    每一层强行sort加权.ans统计最小
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #define ll long long 
    #define _ =read();
    using namespace std;
    const int maxn=1000+100;
    int read(){
        int an=0,f=1;
        char ch=getchar();
        while(!('0'<=ch&&ch<='9')){if(ch=='-');ch=getchar();}
        while('0'<=ch&&ch<='9'){an=an*10+ch-'0';ch=getchar();}
        return an*f;
    }
    vector<int>b[maxn];
    bool vis[maxn];
    int wi[maxn],n;
    int f[maxn],ans[maxn],mi=(int)1e9;
    bool saber(int x,int y){
        return wi[x]>wi[y];
    }
    void dfs(int x){
        vis[x]=1;
        for(int i=0;i<b[x].size();i++){
            if(!vis[ b[x][i] ]){
                dfs(b[x][i]);
            }
        }
        sort(b[x].begin(),b[x].end(),saber);
        for(int i=0;i<b[x].size();i++){
        wi[x]=max(i+1+wi[b[x][i]],wi[x]);
        }
        vis[x]=0;
    }
    int main(){
        n _ 
        for(int i=2;i<=n;i++){
            int x=read();
            b[i].push_back(x);
            b[x].push_back(i);}
        for(int i=1;i<=n;i++){
            dfs(i);
            ans[i]=wi[i];
            mi=min(mi,ans[i]);
            memset(wi,0,sizeof(wi));
        }
        cout<<mi<<endl;
        for(int i=1;i<=n;i++)if(ans[i]==mi)cout<<i<<" ";
        return 0;
    }
    View Code

    by:s_a_b_e_r


    一开始同以为是找重心,然后各种不会做……

    后来看题解发现思路很神奇……

    因为一单位时间每人只能传给一个人,所以这个人周围的节点是依次接到信息的

    于是可以给它周围的节点分配一个边权

    子树越大的节点越要先传递,边权就越小

    所以枚举一遍从哪个点开始向四周传信息

    最后统计最小值以及方案就可以了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=1009;
    int cnt,p[N],n,ans=int(1e9),an[N],f[N];
    bool vis[N];
    struct edge{
    int to,nex;
    }e[N<<1];
    vector<int>q[N];
    bool cmp(int x,int y){return x>y;}
    void add(int u,int v)
    {
         ++cnt;
         e[cnt]=(edge){v,p[u]};
         p[u]=cnt;
    }
    void dfs(int u)
    {
        for(int i=p[u];i;i=e[i].nex)
        {
          int v=e[i].to;
          if(vis[v])continue;
          vis[v]=1;
          dfs(v);
          q[u].push_back(f[v]);
        }
        sort(q[u].begin(),q[u].end(),cmp);
        for(int i=1;i<=q[u].size();++i)
          f[u]=max(f[u],q[u][i-1]+i);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=2;i<=n;++i)
        {
          int x;
          scanf("%d",&x);
          add(x,i);add(i,x);
        }
        for(int i=1;i<=n;++i)
        {
          memset(f,0,sizeof(f));
          memset(vis,0,sizeof(vis));
          for(int j=1;j<=n;++j)q[j].clear();
          vis[i]=1;
          dfs(i);
          an[i]=f[i];
          ans=min(an[i],ans);
        }
        cout<<ans+1<<endl;
        for(int i=1;i<=n;++i)
        if(an[i]==ans)cout<<i<<" ";
        return 0; 
    }
    消息传递

    by:wypx


    s:新机房太棒了

    w:突然换机房……幸福来的好突然



  • 相关阅读:
    hdu 3507 Print Article —— 斜率优化DP
    bzoj 1096 仓库建设 —— 斜率优化DP
    ORDER BY 高级用法之CASE WHEN
    union和union all 的区别
    Ubuntu 链接ln的使用:创建和删除符号链接
    python中set和frozenset方法和区别
    python之sys模块详解
    odoo 8.0 多核启用
    Odoo 中的widget
    Odoo 在 Ubuntu 环境下性能调优
  • 原文地址:https://www.cnblogs.com/ck666/p/7517674.html
Copyright © 2011-2022 走看看