• HDU 4003 Find Metal Mineral (树形DP)


    Find Metal Mineral

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
    Total Submission(s): 1744    Accepted Submission(s): 774


    Problem Description
    Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on Mars to collect them, and due to the unknown reasons, the landing site S of all robots is identified in advanced, in other word, all robot should start their job at point S. Each robot can return to Earth anywhere, and of course they cannot go back to Mars. We have research the information of all paths on Mars, including its two endpoints x, y and energy cost w. To reduce the total energy cost, we should make a optimal plan which cost minimal energy cost.
     
    Input
    There are multiple cases in the input. 
    In each case: 
    The first line specifies three integers N, S, K specifying the numbers of metal mineral, landing site and the number of robots. 
    The next n‐1 lines will give three integers x, y, w in each line specifying there is a path connected point x and y which should cost w. 
    1<=N<=10000, 1<=S<=N, 1<=k<=10, 1<=x, y<=N, 1<=w<=10000.
     
    Output
    For each cases output one line with the minimal energy cost.
     
    Sample Input
    3 1 1 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1
     
    Sample Output
    3 2
    Hint
    In the first case: 1->2->1->3 the cost is 3; In the second case: 1->2; 1->3 the cost is 2;
     
    Source
     
    Recommend
    lcy
     
    树形DP+只能选一个物品的分组背包
    
    dp[pos][num]表示以pos为根节点的子树下,用去num个机器人,所得到的最小值
    特别的是当num==0的时候,dp[pos][0]表示用一个机器人去走完所有子树,最后又回到pos这个节点
    状态转移:dp[pos][num]=min∑{dp[pos_j][num_j]+w_j},pos_j是pos的所有儿子,
    
    
    为了让分组背包只选一个,首先让dp[u][0]如背包
    
    使用一维数组的“分组背包”伪代码如下:
    for 所有的组i
    
        for v=V..0
    
            for 所有的k属于组i
    
                f[v]=max{f[v],f[v-c[k]]+w[k]}

    根据题意可以知道,机器人是可以走回头路的。稍微分析下可以知道,如果从根节点派往子节点如果要折回到根节点,派向这个子节点的机器人越多,产生的重复路径就会越多,所以那么派往这个子节点的个数为1时是最优策略。那么定义DP[i][0]存放1个机器人,从子节点返回到根节点的花费。

    关键是思考:如果 根节点s, 有 n个子节点,那么要怎么样选择才能使dp[s][k]的值最小呢?

    ⑴当机器人的个数为1时,那么只有一种方法,就事用这一个机器人跑遍每个子节点、也就是每次机器人都要从一个子节点返回根节点,然后走向另一个节点,直到遍历所有点位止。那么这种状态下的状态转移为: dp[s][0]=dp[next][0]+2*w;       (其中s为根节点,next为子节点,w为s到next的权值)。

    ⑵当机器人的个数>1时,那么必然存在机器人不必返回根节点的策略。同时由⑴也可以求出折回根节点的花费。

    那么求根节点s下的n个子节点,把每个节点看做一个整体,定义s(n,j)为前n个节点派j个机器人的最小花费,很容易发现这也是个DP,其实就是个背包,s(n-1,j)与s(n,j)必然存在某种联系。可以推出s(n,j)=min(s(n,j), s(n-1,j-k)+dp[v][k]+k*w);  (1<=k<=j,w为s到当前这个子节点v的权值)。因为只要用到上一个子节点的状态,所以对起始点s的所有子节点扫描一遍就可以了。

    其实这题的树形DP,就是 DP套DP。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    const int VM=10010;
    
    struct Edge{
        int to,nxt;
        int cap;
    }edge[VM<<1];
    
    int N,S,K,cnt,head[VM];
    int vis[VM],dp[VM][20]; //dp[i][j]表示以i为根的树用掉j个人。dp[i][0]表示用了一个人又回到上面的点
    
    void addedge(int cu,int cv,int cw){
        edge[cnt].to=cv;
        edge[cnt].cap=cw;
        edge[cnt].nxt=head[cu];
        head[cu]=cnt++;
    }
    
    void DFS(int u){
        if(vis[u])
            return ;
        vis[u]=1;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(!vis[v]){
                DFS(v);
                for(int j=K;j>=0;j--){
                    dp[u][j]+=dp[v][0]+2*edge[i].cap;   //先把dp[u][0]放进背包,保证至少选一个
                    for(int k=1;k<=j;k++)   //  分组背包
                        dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+k*edge[i].cap);
                }
            }
        }
    }
    
    int main(){
    
        //freopen("input.txt","r",stdin);
    
        while(~scanf("%d%d%d",&N,&S,&K)){
            cnt=0;
            memset(head,-1,sizeof(head));
            int u,v,w;
            for(int i=1;i<N;i++){
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w);
                addedge(v,u,w);
            }
            memset(vis,0,sizeof(vis));
            memset(dp,0,sizeof(dp));
            DFS(S);
            printf("%d\n",dp[S][K]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    web图片100%宽度自适应,高度不塌陷
    基于Kafka+ELK搭建海量日志平台
    一句话撸完重量级锁、自旋锁、轻量级锁、偏向锁、悲观、乐观锁等
    MySQL数据库设计规范
    夺命连环问:一个 TCP 连接可以发多少个 HTTP 请求?
    [Kafka]
    ZooKeeper学习总结 第一篇:ZooKeeper快速入门
    Vue图片浏览组件v-viewer,支持旋转、缩放、翻转等操作
    opencv处理验证码python代码
    mac使用pytesseract
  • 原文地址:https://www.cnblogs.com/jackge/p/3090522.html
Copyright © 2020-2023  润新知