题意:给定一棵树图,n个节点,有边权,要派k<11个机器人从节点s出发,遍历所有的点,每当1只机器人经过1条边时就会花费该边的边权,边是可重复走的。问遍历完所有点的最小花费?

思路:

  非常经典,首先需要知道一点,才能往下推理。就是“如果在t点派c个机器人往孩子u,那么最多只有1个机器人能走会回来到t,否则花费总是不划算的”。

  稍微证明一下:

  (1)假设派1个机器人往u,逛一圈回到u的父亲t,花费v= 子树u的边权和*2 + e(t,u)*2。若机器人不要了,那花费肯定比v还要少。

  (2)假设派2个机器人往u,若要2个机器人都回来,显然花费要比(1)要大。若仅要1个机器人回来,花费仍比“仅派1只机器人往u”要高。(可以试试画一棵有3层的树,头两层只有1个节点,第三层节点数随意即可,来模拟一下就知道结果了)

  得到的结论是,要么只派c个机器人去孩子u,且1个都不要走回来(注:0<c<=k);要么派1个机器人出去,且遍历完子树u走回t。

  这样已经很好解决了。枚举下点t的孩子数(组),再枚举点t可能获得的机器人数(容量),再枚举给这个孩子派的机器人数(物品)。

  还有个初始化DP值的问题,因为每个孩子都是必须遍历的,而常规的分组背包是可选(至多选1件)或者不选物品的,那么可以先将“派1个机器人且回收1个机器人的DP值”丢进背包(保证了此容量下肯定有遍历过子树u),然后若有更好的状态再更新掉此容量。

  用DP[t][0]表示“有1个机器人到达t遍历完子树再走回t”的花费。DP[t][i]表示“有i个机器人到达t且遍历完整棵子树t,且不要求回到t”的最小花费。

 #include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <iostream>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=;
struct tower
{
int pri,pow;
}tow[N][]; struct node
{
int from,to,next;
node(){};
node(int from,int to,int next):from(from),to(to),next(next){};
}edge[N*]; int edge_cnt, head[N], cnt[N], dp[N][], n, m ;
void add_node(int from,int to)
{
edge[edge_cnt]=node(from, to, head[from]);
head[from]=edge_cnt++;
}
inline int cmp(tower a,tower b){return a.pri<b.pri;} void DFS(int t,int far)
{
node e;
int flag=;
for(int i=head[t]; i!=-; i=e.next)
{
e=edge[i];
if(e.to==far) continue;
DFS(e.to, t); for(int j=m; j>=; j-- ) //容量
{
dp[t][j]=min(dp[t][j], dp[e.to][]); //先装代价为0的,如果有更好的再代替掉。
for(int k=; k<=j; k++ ) //给此孩子k元,得到的最大攻击力。
dp[t][j]=max(dp[t][j], min(dp[t][j-k], dp[e.to][k]));
}
flag=; //标记是否叶子。
}
if(flag==) memset(dp[t], , sizeof(dp[t])); //叶子节点 //本节点的决策是“仅有1组的分组背包”模型: 必须且最多买1个。(不买就只能靠孩子来防御)
for(int j=m; j>=; j-- ) //容量
{
int k=;
for( ; k<cnt[t] && !tow[t][k].pri; k++ ) //不用钱的,只留1个power最大的.
if(tow[t][k-].pow > tow[t][k].pow)
swap(tow[t][k],tow[t][k-]); for( k-- ; k<cnt[t]; k++) //物品
{
if(j-tow[t][k].pri>=)
dp[t][j]=max(dp[t][j], dp[t][j-tow[t][k].pri] + tow[t][k].pow ); //可以直接挡
}
}
} int main()
{
freopen("input.txt", "r", stdin);
int t, a, b; cin>>t;
while(t--)
{
edge_cnt=;
memset(head, -, sizeof(head));
memset(dp, 0x3f, sizeof(dp)); //注意初始化 scanf("%d",&n);
for(int i=; i<n; i++) //无向图
{
scanf("%d%d",&a,&b);
add_node(a,b);
add_node(b,a);
} scanf("%d",&m); //钱。
for(int i=; i<=n; i++)
{
scanf("%d",&cnt[i]);
for(int j=; j<cnt[i]; j++)
scanf("%d%d", &tow[i][j].pri, &tow[i][j].pow);
sort(tow[i], tow[i]+cnt[i], cmp); //免费的排前面
}
DFS(, -);
printf("%d\n",dp[][m]);
}
return ;
}

AC代码

HDU 4003 Find Metal Mineral (树形DP,经典)的更多相关文章

  1. hdu 4003 Find Metal Mineral 树形DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...

  2. hdu 4003 Find Metal Mineral 树形dp ,*****

    Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Other ...

  3. HDU 4003 Find Metal Mineral(分组背包+树形DP)

    题目链接 很棒的一个树形DP.学的太渣了. #include <cstdio> #include <string> #include <cstring> #incl ...

  4. HDU4003Find Metal Mineral[树形DP 分组背包]

    Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Other ...

  5. HDU4003 Find Metal Mineral 树形DP

    Find Metal Mineral Problem Description Humans have discovered a kind of new metal mineral on Mars wh ...

  6. HDU-4003 Find Metal Mineral 树形DP (好题)

    题意:给出n个点的一棵树,有k个机器人,机器人从根节点rt出发,问访问完整棵树(每个点至少访问一次)的最小代价(即所有机器人路程总和),机器人可以在任何点停下. 解法:这道题还是比较明显的能看出来是树 ...

  7. hdu4003Find Metal Mineral(树形DP)

    4003 思维啊 dp[i][j]表示当前I节点停留了j个机器人 那么它与父亲的关系就有了 那条边就走了j遍 dp[i][j] = min(dp[i][j],dp[child][g]+dp[i][j- ...

  8. HDU 4003 Find Metal Mineral

    这个题是POJ1849的加强版. 先说一个很重要的结论,下面两种方法都是从这个结论出发的. 一个人从起点遍历一颗树,如果最终要回到起点,走过的最小权值就是整棵树的权值的2倍. 而且K个人的情况也是如此 ...

  9. hdu 4514 并查集+树形dp

    湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Tot ...

随机推荐

  1. jQuery基本语法2

    jQuery事件 一:jQuery鼠标事件 click单击 dbclick双击 $ele.click()不带任何参数一般是用来指定触发一个事件 $ele.click( handler(eventObj ...

  2. Android开发相关工具(eclipse篇)

    ADT 安装该工具后才能配置Android SDK包,使可以在eclipse里开发Android程序 AVD Android模拟器管理工具,创建删除Android模拟器 SDK Manager And ...

  3. 2-1赋值运算符 & 2-2自增自减运算符 &2-3

    2-1赋值运算符 先定义一个变量,把定义好的变量在赋值给另外一个变量.变向之间的互相赋值 2-2自增自减运算符 元素符,放在变量前和变量后的区别 先进行自增运算,再进行赋值运算.这里先进行num1的+ ...

  4. ios NSFileManager创建目录、文件

    NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *str1 = NSHomeDirectory(); _fi ...

  5. html上传多图并预览

    涉及知识:base64处理图片,ajax,js,thinkphp 效果图: 代码实现: html: <!DOCTYPE html> <html> <head> &l ...

  6. Lightoj1003【判环操作】

    题意: 对于n个给出字符串a,b,理解成a在b之前办好这个事情,要求n个给出两个串,a都要在b之前完成: 题意: 所以一旦出现环就不行了: 以前在写最短路的时候,spfa就有一个判环,后来写着写着写到 ...

  7. Tessellation

    Tessellation细分曲面技术是AMD(ATI)常年研发多代的技术,经过多年发展最终被采纳成为DX11的一项关键技术,因此历来都是宣传重点.和光线追踪不同,现在的光栅化图形渲染技术的核心是绘制大 ...

  8. C\C++书籍

    原文链接: bert hubert   翻译: 伯乐在线- 周昌鸿译文链接: http://blog.jobbole.com/61308/ 人们常常问我有什么C++和编程的书籍推荐,也许是因为我在Po ...

  9. 洛谷P3723 [AH2017/HNOI2017]礼物(FFT)

    传送门 首先,两个数同时增加自然数值相当于只有其中一个数增加(此增加量可以小于0) 我们令$x$为当前的增加量,${a},{b}$分别为旋转后的两个数列,那么$$ans=\sum_{i=1}^n(a_ ...

  10. css-float浮动详细

    前言 pc端的页面为了保持良好的兼容性,一般会使用css2部分就支持的浮动(float)和定位(postion)来布局.浮动行为怪异,但有迹可循.以下下是在css揭秘一书中总结的浮动内幕. 包含块:浮 ...