zoukankan      html  css  js  c++  java
  • 算法提高 金属采集_树形dp

    算法提高 金属采集  
    时间限制:1.0s   内存限制:256.0MB
          
    问题描述

    人类在火星上发现了一种新的金属!这些金属分布在一些奇怪的地方,不妨叫它节点好了。一些节点之间有道路相连,所有的节点和道路形成了一棵树。一共有 n 个节点,这些节点被编号为 1~n 。人类将 k 个机器人送上了火星,目的是采集这些金属。这些机器人都被送到了一个指定的着落点, S 号节点。每个机器人在着落之后,必须沿着道路行走。当机器人到达一个节点时,它会采集这个节点蕴藏的所有金属矿。当机器人完成自己的任务之后,可以从任意一个节点返回地球。当然,回到地球的机器人就无法再到火星去了。我们已经提前测量出了每条道路的信息,包括它的两个端点 x 和 y,以及通过这条道路需要花费的能量 w 。我们想花费尽量少的能量采集所有节点的金属,这个任务就交给你了。

    输入格式

    第一行包含三个整数 n, S 和 k ,分别代表节点个数、着落点编号,和机器人个数。

    接下来一共 n-1 行,每行描述一条道路。一行含有三个整数 x, y 和 w ,代表在 x 号节点和 y 号节点之间有一条道路,通过需要花费 w 个单位的能量。所有道路都可以双向通行。

    输出格式
    输出一个整数,代表采集所有节点的金属所需要的最少能量。
    样例输入
    6 1 3
    1 2 1
    2 3 1
    2 4 1000
    2 5 1000
    1 6 1000
    样例输出
    3004
    样例说明

    所有机器人在 1 号节点着陆。

    第一个机器人的行走路径为 1->6 ,在 6 号节点返回地球,花费能量为1000。

    第二个机器人的行走路径为 1->2->3->2->4 ,在 4 号节点返回地球,花费能量为1003。

    第一个机器人的行走路径为 1->2->5 ,在 5 号节点返回地球,花费能量为1001。

    数据规模与约定

    本题有10个测试点。

    对于测试点 1~2 , n <= 10 , k <= 5 。

    对于测试点 3 , n <= 100000 , k = 1 。

    对于测试点 4 , n <= 1000 , k = 2 。

    对于测试点 5~6 , n <= 1000 , k <= 10 。

    对于测试点 7~10 , n <= 100000 , k <= 10 。

    道路的能量 w 均为不超过 1000 的正整数。

    解题思路: 

    如果没做过树形dp的可以先做poj2342,大体思路跟那个很像,不过一个点可以放多个机器人。

    这样每个点就可以有0,1,2,3、、、个机器人了,就有这么多状态。

    每个节点储存以这个节点为根的整个树的花费的最少能量。

    然后由整棵树的根节点开始,他跟它的子节点有关系,已知需经历过所有的节点。

    可以留在子节点0个--k个机器人,当0个的时候也一定要派一个机器人去,所以:

    (dp[m][k]表示以m节点为根的树,来k个机器人花费的最少能量)

     dp[root][j]+=dp[tree[root].son[i].to][0]+2*tree[root].son[i].spend;//等于子节点存0个机器人+一个机器人从父节点到子节点,再从子节点到父节点(即2*cost)。
    dp[root][j]=min(   dp[root][j],     dp[root][j-l] + dp[tree[root].son[i].to][l]+l*tree[root].son[i].spend      );//但子节点也可能停留0到j个机器人,所以需要循环一遍再来更新dp[root][j]的值。  我这里用min()函数报错呢,就改成if了。。。
    第二个dp里面有j-l,l是从0开始的,如果j从0开始,j-l就成负的了,这里要注意j那个循环要从k开始。
     
    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <map>
    #include <cmath>
    #include <stack>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #define FOR(i,x,n) for(long i=x;i<n;i++)
    #define ll long long int
    #define INF 0x3f3f3f3f
    #define MOD 1000000007
    #define MAX_N 60
    #define MAX_M 1005
    
    using namespace std;
    
    struct node2{int to;int spend;};
    //struct node2 edge;
    
    struct node{
        int number;
        int rating;
        vector<node2> son;//编号,花费
        int father;
    };
    node tree[100005];
    int visable[100005];
    int dp[100005][12];//0表示不去,1表示去
    int n,S,k;
    
    void dfs(int root){
        visable[root]=1;
        FOR(i,0,tree[root].son.size()){
            if(!visable[tree[root].son[i].to]){
                dfs(tree[root].son[i].to);
                for(int j=k;j>=0;j--){//注意0的时候也要循环
                    dp[root][j]+=dp[tree[root].son[i].to][0]+2*tree[root].son[i].spend;
                    FOR(l,1,j+1){
                        if(dp[root][j-l]+dp[tree[root].son[i].to][l]+l*tree[root].son[i].spend<dp[root][j]){
                            dp[root][j]=dp[root][j-l]+dp[tree[root].son[i].to][l]+l*tree[root].son[i].spend;
                        }
                    }
                }
            }
    
    
        }
    }
    
    int main()
    {
        //freopen("input1.txt", "r", stdin);
        //freopen("data.out", "w", stdout);
        int t1,t2,t3;
        scanf("%d %d %d",&n,&S,&k);
        memset(visable,0,sizeof(visable));
        memset(dp,0,sizeof(dp));
        FOR(i,1,n){
            scanf("%d %d %d",&t1,&t2,&t3);
            node2 t={t2,t3};
            node2 tt={t1,t3};
            tree[t1].son.push_back(t);
            tree[t2].son.push_back(tt);
        }
        dfs(S);
        printf("%d",dp[S][k]);
        //fclose(stdin);
        //fclose(stdout);
        return 0;
    }
  • 相关阅读:
    android学习笔记--AlarmManager
    Linux学习笔记--vi
    perl学习笔记--搭建开发环境
    PERL学习笔记---正则表达式的应用
    PERL学习笔记---正则表达式
    perl学习笔记---标量
    产生0到100内的任意随机数
    js判断参数是否为非数字
    linux 下搭建php环境
    关于echarts的疑问
  • 原文地址:https://www.cnblogs.com/TWS-YIFEI/p/6657386.html
Copyright © 2011-2022 走看看