zoukankan      html  css  js  c++  java
  • HDU-4003 Find Metal Mineral 树形DP (好题)

    题意:给出n个点的一棵树,有k个机器人,机器人从根节点rt出发,问访问完整棵树(每个点至少访问一次)的最小代价(即所有机器人路程总和),机器人可以在任何点停下。

    解法:这道题还是比较明显的能看出来是树形DP,然后分配机器人肯定想到树形分组背包DP。那么dp方程和常规树形背包dp一样很容易些 dp[x][i]=min(dp[x][i],dp[y][j]+val(y,j)+dp[x][i-j]) 代表总共i个机器人给当前子树y分配j个机器人剩下的i-j个机器人分配给前几棵子树的最小代价。主要问题就是转移代价怎么写?明显如果机器人数量>=叶子结点数量就直接每个叶子派一个就行,否则必须得重复使用。仔细观察得到其实只要特殊处理派机器人为0的情况就行,派机器人>0的直接dp,且容易得到派机器人为0就是的代价就是  子树大小*2  (因为要从分叉点进去访问这棵子树之后再回到这个分叉点,画图很容易理解)。所以特殊处理机器人=0,其他代价就是dp[y][j]+j*w。有点绕,配合代码看会容易理解一些。 

    总的来说,这是一道好题,不容易想很锻炼思维(至少对博主来说是这样)。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e4+10;
    int n,m,rt;
    int siz[N],dp[N][15],tmp[15];
    
    int cnt,head[N],nxt[N<<1],to[N<<1],len[N<<1];
    void add_edge(int x,int y,int z) {
        nxt[++cnt]=head[x]; to[cnt]=y; len[cnt]=z; head[x]=cnt;
    }
    
    int calc(int y,int k,int i) {
        if (k==0) return dp[y][k]+2*len[i]; else return dp[y][k]+k*len[i];
    }
    
    void dfs(int x,int fa) {
        siz[x]=0;
        bool ok=1;
        memset(dp[x],0x3f,sizeof(dp[x])); dp[x][0]=0;
        for (int i=head[x];i;i=nxt[i]) {
            int y=to[i];
            if (y==fa) continue;
            dfs(y,x); ok=0;
            siz[x]+=siz[y]+len[i];
            memcpy(tmp,dp[x],sizeof(dp[x]));
            memset(dp[x],0x3f,sizeof(dp[x]));
            for (int j=m;j;j--)
                for (int k=0;k<=j;k++)  //给子节点y分配k个机器人 
                    dp[x][j]=min(dp[x][j],calc(y,k,i)+tmp[j-k]);
            dp[x][0]=2*siz[x];        
        }
        if (ok) memset(dp[x],0,sizeof(dp[x]));
    }
    
    int main()
    {
        while (scanf("%d%d%d",&n,&rt,&m)==3) {
            cnt=1; for (int i=1;i<=n;i++) head[i]=0;
            for (int i=1;i<n;i++) {
                int x,y,z; scanf("%d%d%d",&x,&y,&z);
                add_edge(x,y,z);
                add_edge(y,x,z);
            }
            dfs(rt,0);
            int ans=0x3f3f3f3f;
            for (int i=0;i<=m;i++) ans=min(ans,dp[rt][i]);
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    分享一个单例模型类Singleton代码
    异步 HttpContext.Current实现取值的方法(解决异步Application,Session,Cache...等失效的问题)
    httpwebrequest 用GET方法时报无法发送具有此谓词类型的内容正文
    Oracle 存储过程的导出导入序列的导出
    通用后台模版的实现
    java流类基础练习。
    java流。基础
    java流类、、、理解不够,流太多不知怎么用好?
    java代码流类。。程序怎么跟书上的结果不一样???
    java代码流类
  • 原文地址:https://www.cnblogs.com/clno1/p/11184989.html
Copyright © 2011-2022 走看看