zoukankan      html  css  js  c++  java
  • 【POJ2631】Roads in the North【树的直径】

    题目大意:

    题目链接:http://poj.org/problem?id=2631
    求一棵树的直径。


    思路:

    树的直径模板题。

    方法一:

    树形DPDP求输的直径。
    考虑以11为根节点,求出f[i]f[i]表示从ii到以ii为根的子树的任意节点的最大路径和。那么很明显有
    f[i]=max(f[i],f[j]+dis[i][j])(json[i])f[i]=max(f[i],f[j]+dis[i][j])(jin son[i])
    那么再考虑求出g[i]g[i]表示经过ii的路径中的最大路径和。
    那么假设在该路径上有两点xxyy,那么就有
    g[i]=max(g[i],f[x]+dis[x][i]+dis[i][y]+f[y])g[i]=max(g[i],f[x]+dis[x][i]+dis[i][y]+f[y])
    此时如果枚举xxyy,时间复杂度就是O(n3)O(n^3),十分不理想。
    其实根本没有必要枚举xxyy。我们在求f[i]f[i]时,就有f[i]=max(f[y]+dis[i][y])(yson[i])f[i]=max(f[y]+dis[i][y])(yin son[i])。那么如果此时我们有枚举到了ii的下一个子节点xx,那么此时我们就有了

    • f[y]+dis[i][y]f[y]+dis[i][y]
    • f[x]f[x]
    • dis[x][i]dis[x][i]

    那么久可以直接更新g[i]g[i]了!
    其实可以根本不用g[i]g[i]这个数组,直接用ansans求直径。

    • 树形DPDP代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=10100;
    int n,x,y,z,tot,ans,f[N],head[N];
    
    struct edge
    {
    	int to,dis,next;
    }e[N*2];
    
    void add(int from,int to,int dis)
    {
    	e[++tot].to=to;
    	e[tot].dis=dis;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dp(int x,int fa)
    {
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int y=e[i].to;
    		if (y==fa) continue;
    		dp(y,x);
    		ans=max(ans,f[x]+f[y]+e[i].dis);  //求直径
    		f[x]=max(f[x],f[y]+e[i].dis);  //更新
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	while (scanf("%d%d%d",&x,&y,&z)==3)
    	{
    		add(x,y,z);
    		add(y,x,z);
    	}
    	dp(1,0);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    方法二:搜索

    我们先从11开始搜索,可以求出一个与11之间路径和最大的点pp。那么此时点p肯定是树的其中一条直径的起点,终点肯定是与p距离最远的点q,树的直径就是p到q的路径和
    还是比较好理解的。在这就不过多赘述。

    • 搜索代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=10100;
    int n,x,y,z,tot,p,head[N],f[N],maxn;
    
    struct edge
    {
    	int next,dis,to;
    }e[N*2];
    
    void add(int from,int to,int dis)
    {
    	e[++tot].to=to;
    	e[tot].dis=dis;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void dfs(int x,int fa,int s)
    {
    	if (s>maxn)  //从起点能到达最远的点
    	{
    		maxn=s;
    		p=x;
    	}
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int y=e[i].to;
    		if (y==fa) continue;
    		dfs(y,x,s+e[i].dis);
    	}
    	return;
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	while (scanf("%d%d%d",&x,&y,&z)==3)
    	{
    		add(x,y,z);
    		add(y,x,z);
    	}
    	dfs(1,0,0);
    	maxn=0;
    	dfs(p,0,0);
    	printf("%d
    ",maxn);
    	return 0;
    }
    
  • 相关阅读:
    Git 菜鸟变大神 (一) 本地仓库的创建和初始化
    Dubbo项目实战 (二) 注册中心zookeeper-3.4.6集群以及高可用
    Dubbo项目实战 (一)服务划分粒度
    枚举类的理解和应用
    全文检索原理及实现方式
    MinIO简介和java Api的使用
    js金额转中文大写
    文档相关工具
    JS特殊监听方法
    注解的使用、拦截器使用、AOP切面使用
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998452.html
Copyright © 2011-2022 走看看