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;
    }
    
  • 相关阅读:
    关于lockkeyword
    关于多层for循环迭代的效率优化问题
    Android 面试精华题目总结
    Linux基础回想(1)——Linux系统概述
    linux源代码编译安装OpenCV
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem B. Matrix Fast Power
    校赛热身 Problem B. Matrix Fast Power
    集合的划分(递推)
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998452.html
Copyright © 2011-2022 走看看