zoukankan      html  css  js  c++  java
  • HDU 2196(树形dp)

    Problem

    HDU 题目地址

    题意简述:给一个 (n) 个点的带边权树,求每个点能到的最远距离。

    Solution

    以前做过一遍没有理解透,现在理解透了。

    题目要求每个点的答案,一般要用换根dp。这里有一种换根dp的实现方法————扫两次。

    (dp[i,0/1/2]) 表示 (i) 点:(0) 向下延伸的最远距离,(1) 向下延伸的次远距离(且不与最远距离的路径重合),(2) 向上延伸的最远距离。其中 (0,1) 由第一次扫描得到,(2) 由第二次扫描得到,具体的:

    (w)(i->j) 这条边的权值,在第一次 Dfs(扫描)中:

    [dp[i,0] = max_{j in son_i}{dp[j,0] + w} ]

    令上述中最大的 (j)(k) 点,那么

    [dp[i,1] = max{max_{j in son_i,j ≠ k}{dp[j,0] + w},dp[k,1] + w} ]

    在第二次扫描中,(w) 类似:

    如果 (i) 点是 (fa_i) 最远距离上的点 (dp[i,2] = max{dp[fa_i,1],dp[fa_i,2]} + w)

    否则 (dp[i,2] = max{dp[fa_i,0],dp[fa_i,2]} + w)

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read() {
    	int x=0,f=1; char ch=getchar();
    	while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    	while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    	return x * f;
    }
    const int N = 1e5+7;
    int n,cnt;
    int head[N];
    int f[N][3];
    struct Edge {
    	int next,to,w;
    }edge[N<<1];
    inline void add(int u,int v,int w) {
    	edge[++cnt] = (Edge)<%head[u],v,w%>;
    	head[u] = cnt;
    }
    void Dfs1(int u,int fa) {
    	int Mxk = 0;
    	for(int i=head[u];i;i=edge[i].next) {
    		int v = edge[i].to, w = edge[i].w;
    		if(v == fa) continue;
    		Dfs1(v,u);
    		if(f[v][0]+w >= f[u][0]) f[u][1] = f[u][0], f[u][0] = f[v][0]+w;
    		else if(f[v][0]+w > f[u][1]) f[u][1] = f[v][0]+w; 
    	}
    }
    void Dfs2(int u,int fa,int prew) {
    	if(f[fa][0] == f[u][0]+prew) f[u][2] = f[fa][1] + prew;
    	else f[u][2] = f[fa][0] + prew;
    	f[u][2] = max(f[u][2],f[fa][2]+prew);
    	for(int i=head[u];i;i=edge[i].next) {
    		int v = edge[i].to, w = edge[i].w;
    		if(v == fa) continue;
    		Dfs2(v,u,w);
    	}
    }
    void test() {
    	puts("test");
    	for(int i=1;i<=n;++i)
    		printf("	%lld %lld %lld
    ",f[i][0],f[i][1],f[i][2]);
    	puts("--End--");
    }
    void work() {
    	memset(head, 0, sizeof(head)); cnt = 0;
    	memset(f, 0, sizeof(f));
    	for(int i=2,fa,w;i<=n;++i) {
    		fa = read(), w = read();
    		add(i,fa,w), add(fa,i,w);
    	}
    	Dfs1(1,0); Dfs2(1,0,0);
    	//test();
    	for(int i=1;i<=n;++i)
    		printf("%lld
    ",max(max(f[i][0],f[i][1]),f[i][2]));
    }
    signed main()
    {
    	while(~scanf("%lld",&n))
    		work();
    	return 0;
    }
    /*
    5
    1 1
    2 1
    3 1
    1 1
    
    3
    2
    3
    4
    4
    */
    

    Summary

    无。

  • 相关阅读:
    Redis
    Ajax和JSON
    快速幂
    欧拉函数
    约数
    质数
    二分图相关算法模板
    最小生成树模板
    最短路算法模板
    康托展开和逆康托展开
  • 原文地址:https://www.cnblogs.com/BaseAI/p/12267354.html
Copyright © 2011-2022 走看看