HDU4003 树上的分组背包

题目大意

我们在s节点上有k个机器人,现在我们派遣这k个机器人出去随便走,要求在最短距离里遍历整棵树

题目分析

这是树上的分组背包
什么是树上的分组背包?
假如说一个节点有i个儿子节点,那么就有i组物品,对于每个儿子的所有状态,只能选一个,就是分组背包,大家都知道分组背包伪代码:

for 所有的组k
    for 所有的物品i属于组k
        for j=W...w[i]
        f[j]=max(f[j],f[j-w[i]]+v[i]);

至于树上的分组背包,也差不多。
但是对于此题,我们用f[i][j]表示i节点为根的子树被派遣了j个机器人的最优解,对于每一个儿子节点,对那个子树派遣多少机器人就是物品。每组我们必须选一个物品,处理方案是每次强制把f[son][0]装入背包。
至于怎么处理走的路程的问题,如果不派遣机器人到这颗子树,也就是让一个机器人到这棵子树里转一圈然后回来,所以就是f[son][0]+dis[x][son]*2;
接下来的方程自己分析一下吧,也可以看看代码。

代码

#include<iostream>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
int read(){
    int q=0,w=1;char ch=' ';
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')q=q*10+ch-'0',ch=getchar();
    return q*w;
}
int n,s,num,tot;
int h[10005],ne[20005],to[20005],mon[20005];
int f[10005][12];
void add(int x,int y,int z){to[++tot]=y;mon[tot]=z;ne[tot]=h[x];h[x]=tot;}
void dfs(int x,int las){
    for(int i=h[x];i!=-1;i=ne[i]){
        if(to[i]==las)continue;
        dfs(to[i],x);
        for(int k=num;k>=0;k--){//以x为根的子树放k个机器人
            f[x][k]+=f[to[i]][0]+mon[i]*2;//不派遣机器人到那个子树
            for(int j=1;j<=k;j++)
            f[x][k]=min(f[x][k],f[x][k-j]+f[to[i]][j]+j*mon[i]);
        }
    }
}
int main()
{
    int i,j,x,y,z;
    while(scanf("%d%d%d",&n,&s,&num)==3){
    memset(h,-1,sizeof(h));tot=0;
    memset(f,0,sizeof(f));
    for(i=1;i<=n-1;i++){x=read();y=read();z=read();add(x,y,z);add(y,x,z);}
    dfs(s,-1);printf("%d\n",f[s][num]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值