zoukankan      html  css  js  c++  java
  • HDU2196-Computer

    原题连接:

    http://acm.hdu.edu.cn/showproblem.php?pid=2196


    思路:

    好了,无敌了,经过昨晚4个钟头+今上午1个小时的奋战,这题终于被我AC了

    收获的确是不小。。呵呵

    一步步的总结吧,题意就是让你求给定树中某一个点到其他任意点的最大权值

    (1)总体的思路。一个点到其他任意点的最大权值只有两种可能性,一个是这个值来自的子树,另一个是这个值来自父结点,因为这个点通往外界的出口就只有这两条了

    (2)首先是求出子树的最大权值,这个只需要用一个dfs+记忆化搜索,这里之所以dfs一个根结点就可以得到所有点的f[i][0]是因为,在遍历所有叶子的过程中,它实际就是路过了所有的结点——只有这样才有可能便利到所有的叶子。

    (3)其次要求每个节点的f[i][1],即通过自己的父节点能够达到的最大权值,那么这个值有两种可能性。就这一块纠结了能有几个小时,如果在一开始就很严密的给总结好,就不会有那么多的麻烦了。一是父节点的其他分支,(注!如果这个分枝不存在,那么这个值就是w)另一个是父节点的父节点,我们在这两个值中选择一个更大的赋给f[i][1]。

    (4)还有一个坑了好久的地方是求某节点到叶子的第二长距离,这个也是要考虑到所有的大小可能性,然后仔细的做好分类

    (5)最后说一下这个题的数据结构,即树的存储方式。用了一个struct里面带着两个变量v和w来存储子树和到达子树的距离,然后用一个root数组来存父节点的位置。

    (6)last but not least,这个题在网上好像所有人都是用的两个dfs的做法,而我自创了一个dfs+bfs的做法,或许5个h就是代价吧。。。


    #include <iostream>
    #include <vector>
    #include <cstring>
    #include <queue>
    #define MAX 10007
    using namespace std;
    
    int n;
    int max(int a,int b)
    {
        return a>b?a:b;
    }
    struct node {
        int v,w;
    };
    vector<node> son[MAX];
    __int64 f[MAX][3];
    __int64 dp[MAX];
    int root[MAX];
    queue<int> q;
    int end[MAX];
    
    __int64 dfs1(int s)
    {
        if(f[s][0] != -1) return f[s][0];
        else {
            int len = son[s].size();
            for(int i = 0;i < len;i++)
            {
                int v = son[s][i].v;
                int w = son[s][i].w;
                int nn = w+dfs1(v);
                if(nn>f[s][0]) {
                    if(f[s][0] == f[s][2]) 
                        f[s][0] = nn;
                    else {
                        f[s][2] = f[s][0];
                        f[s][0] = nn;
                    }
                }
                else if(nn>f[s][2]) 
                    f[s][2] = nn;
            }
            return f[s][0];
        }
    }
    
    void bfs()
    {
        while(!q.empty())
        {
            int s = q.front();
            q.pop();    
            int len = son[s].size();
            for(int i = 0;i < len;i++)
            {
                int v = son[s][i].v;
                int w = son[s][i].w;
                
                if(f[v][0]+w != f[s][0]) 
                    f[v][1] = f[s][0]+w;
                else {
                    if(f[s][2] != -1)
                        f[v][1] = w+f[s][2];
                    else 
                        f[v][1] = w;
                }
                
                f[v][1] = max(f[v][1],f[s][1]+w);
                
                dp[v] = max(f[v][0],f[v][1]);
                q.push(v);
            }
        }
    } 
    
    int main()
    {
        while(cin>>n)
        {
            memset(root,-1,sizeof(root));
            for(int i = 1;i <= n;i++)
                son[i].clear();
            int v,w;
            for(int i = 2;i <= n;i++) 
            {
                    cin>>v>>w;
                //构建树 
                node tmp;
                tmp.v = i;
                tmp.w = w;
                son[v].push_back(tmp);
                root[i] = v;
            }
            memset(f,-1,sizeof(f));
            for(int i = 1;i <= n;i++)
                if(son[i].empty()) 
                    f[i][0] = 0;
            //dfs求所有的点到叶子节点的最长距离 
            dfs1(1);
            //bfs求所有点的f[i][1] 
            memset(dp,-1,sizeof(dp));
            dp[1] = f[1][0];//树根节点已经成为了男人 
            q.push(1);
            bfs();
            
            for(int i = 1;i <= n;i++)
                cout<<dp[i]<<endl; 
        }
        return 0;
    }
  • 相关阅读:
    HOJ 2139 Spiderman's workout(动态规划)
    FZU 2107 Hua Rong Dao(dfs)
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 计算机存储中有多少字节
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 合法括号序列
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
    Java 第十一届 蓝桥杯 省模拟赛 无向连通图最少包含多少条边
  • 原文地址:https://www.cnblogs.com/immortal-worm/p/5144244.html
Copyright © 2011-2022 走看看