zoukankan      html  css  js  c++  java
  • P2018 消息传递[dp]

    题目描述

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

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

    现在,你想知道:

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

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

    解析

    拿到题看错了,以为是一开始可以告诉任意多个人,然后想了好久都想不出来。。。

    如果一开始只告诉一个人就好办很多。

    分析题目,容易看出对于一个以(x)为根的子树,其传播完毕的时间就是其最大子树(包含节点最多)的节点个数(+1)

    (dp[x])表示一开始把消息告诉(x),传播完毕的最短时间。

    那么做法就很显然了,我们考虑状态转移。对于节点(x),我们遍历它的所有儿子节点,找出能使得传播完以(x)为根的子树的最短时间。其实就是找最优情况下的最短时间,显然,从(x)传播到(x)的最大子树是当前最优情况。


    题目中提到,每单位时间一个人只能告诉另一个人,而不是多个人。因此最短时间不一定等于最优情况下从(x)的最大子树传播到(x)的时间,但是最优情况下(x)一定要最先告诉(x)的最大子树。那么考虑(x)的其它儿子,(x)的传播到这些儿子所需的时间有可能比传播到(x)的最大子树的时间还要长。

    参考代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<cstdlib>
    #include<queue>
    #include<vector>
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    #define N 1010
    #define MOD 2520
    #define E 1e-12
    using namespace std;
    inline int read()
    {
    	int f=1,x=0;char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    struct rec{
    	int ver,next;
    }g[N<<1];
    int head[N],tot,dp[N],n;
    inline void add(int x,int y)
    {
    	g[++tot].ver=y;
    	g[tot].next=head[x],head[x]=tot;
    }
    inline int dfs(int x,int fa)
    {
    	dp[x]=0;vector<int> vec;
    	for(int i=head[x];i;i=g[i].next){
    		int y=g[i].ver;
    		if(y==fa) continue;
    		dfs(y,x);
    		vec.push_back(dp[y]);
    	}
    	sort(vec.begin(),vec.end());
    	int len=vec.size(),tmp=0;
    	for(int i=0;i<len;++i)
    		tmp=max(tmp,vec[i]+len-i-1);
    	dp[x]=tmp+1;
    }
    int main()
    {
    	n=read();
    	for(int i=2;i<=n;++i){
    		int x=read();
    		add(i,x),add(x,i);
    	}
    	int maxx=INF;
    	vector<int> ans;
    	for(int i=1;i<=n;++i){
    		dfs(i,-1);
    		if(maxx>dp[i]){
    			maxx=dp[i];
    			ans.clear();
    			ans.push_back(i);
    		}
    		else if(maxx==dp[i])
    			ans.push_back(i);
    	}
    	cout<<maxx<<endl;
    	sort(ans.begin(),ans.end());
    	for(int i=0;i<ans.size();++i)
    		printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    如何手动编译运行带包 java 程序
    java计算时间差 Java问题通用解决代码
    Java除法结果带小数、进一法的实现 Java问题通用解决代码
    java中按字节获得字符串长度的两种方法 Java问题通用解决代码
    java精确除法计算,四舍五入 Java问题通用解决代码
    java 根据生日计算年龄 Java问题通用解决代码
    java统计中英文字数 Java问题通用解决代码
    java 实现新浪微博内容计数器 Java问题通用解决代码
    java代理ip有效检测
    java 实现统计某段文字在内容中出现的次数
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/11694248.html
Copyright © 2011-2022 走看看