树形DP-----HDU4003 Find Metal Mineral
Find Metal Mineral
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others) Total Submission(s): 2371 Accepted Submission(s): 1079
3 1 1 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1
In the first case: 1->2->1->3 the cost is 3; In the second case: 1->2; 1->3 the cost is 2;
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的所有儿子,
当num_j==0的时候,和别的时候不同,特别处理一下就好。
状态转移并不难,最精华的,我不认为是状态转移,而是转移时使用的那个“分组背包”思想。
使用一维数组的“分组背包”伪代码如下:
for 所有的组i
for v=V..0
for 所有的k属于组i
f[v]=max{f[v],f[v-c[k]]+w[k]}
#include <iostream>
#include <cstdio>
#include <cstring> using namespace std; struct Edge{
int to;
int value;
int next;
}edge[*];
int head[],dp[][];
int N,S,K,total; inline int MIN(int a,int b)
{
if(a<b) return a;
return b;
}
void addEdge(int start,int end,int value)
{
edge[total].to=end;edge[total].value=value;
edge[total].next=head[start];head[start]=total++; edge[total].to=start,edge[total].value=value;
edge[total].next=head[end],head[end]=total++;
} void DP(int source,int pre)
{
for(int i=head[source];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(to==pre) continue;
DP(to,source);
for(int j=K;j>=;j--)
{
dp[source][j]+=dp[to][]+*edge[i].value;
for(int k=;k<=j;k++)
dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);
}
}
} int main()
{
while(scanf("%d %d %d",&N,&S,&K)!=EOF)
{
memset(dp,,sizeof(dp));
memset(head,-,sizeof(head));
total=; int x,y,cost;
for(int i=;i<N;i++)
{
scanf("%d %d %d",&x,&y,&cost);
addEdge(x,y,cost);
}
DP(S,-);
printf("%d\n",dp[S][K]);
}
return ;
}
思路和其他人差不多,谈谈自己是怎么理解的吧:
首先,用两数组建立无向树,还是第一次,费了不少功夫。定义一个结构代表边edge[i]={to,next,value},其中edge[i]表示第i条边,to是边的末点,value就不说了,next代表的是同一父节点边方向相同的与此边相邻的左边的边的编号,其中最左是-1。以此为基础建立一个边数组(注意数组大小是顶点数的两倍),还有用一个head[i]数组来表示最右边的边的编号。
解释这一段代码,当时写的理解的不是很好:
void DP(int source,int pre)
{
for(int i=head[source];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(to==pre) continue;
DP(to,source);
for(int j=K;j>=;j--)
{
dp[source][j]+=dp[to][]+*edge[i].value;
for(int k=;k<=j;k++)
dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);
}
}
}
第一层for循环查找与节点source相连的各条边,to是此边对应的末点,若此边是叶子节点则to==pre(由于节点最左边的边访问完以后,只有到他父节点的边,这里只能用continue,因为不确定访问的顺序,return不合适),递归访问子节点此时应用01背包,由于dp[source][0]比较特殊单独处理,一棵子树对应一个分组,dp[source][j]=MIN(dp[source][j],dp[source][j-k]+dp[to][k]+k*edge[i].value);也比较好理解。
树形DP-----HDU4003 Find Metal Mineral的更多相关文章
- 【树形dp】Find Metal Mineral
[HDU4003]Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (J ...
- HDU4003 Find Metal Mineral 树形DP
Find Metal Mineral Problem Description Humans have discovered a kind of new metal mineral on Mars wh ...
- HDU-4003 Find Metal Mineral 树形DP (好题)
题意:给出n个点的一棵树,有k个机器人,机器人从根节点rt出发,问访问完整棵树(每个点至少访问一次)的最小代价(即所有机器人路程总和),机器人可以在任何点停下. 解法:这道题还是比较明显的能看出来是树 ...
- HDU4003 Find Metal Mineral
看别人思路的 树形分组背包. 题意:给出结点数n,起点s,机器人数k,然后n-1行给出相互连接的两个点,还有这条路线的价值,要求最小花费 思路:这是我从别人博客里找到的解释,因为很详细就引用了 dp[ ...
- HDU-4003 Find Metal Mineral (树形DP+分组背包)
题目大意:用m个机器人去遍历有n个节点的有根树,边权代表一个机器人通过这条边的代价,求最小代价. 题目分析:定义状态dp(root,k)表示最终遍历完成后以root为根节点的子树中有k个机器人时产生的 ...
- HDU4003Find Metal Mineral[树形DP 分组背包]
Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Other ...
- hdu 4003 Find Metal Mineral 树形DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Humans have discovered a kind of new metal miner ...
- hdu 4003 Find Metal Mineral 树形dp ,*****
Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Other ...
- HDU 4003 Find Metal Mineral(分组背包+树形DP)
题目链接 很棒的一个树形DP.学的太渣了. #include <cstdio> #include <string> #include <cstring> #incl ...
- hdu4003详解(树形dp+多组背包)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003 Find Metal Mineral Time Limit: 2000/1000 MS (Jav ...
随机推荐
- Timer的异常
定时任务用Timer实现有可能出现异常,因为它是基于绝对时间而不是相对时间进行调度的.当环境的系统时间被修改后,原来的定时任务可能就不跑了.另外需要注意一点,捕获并处理定时任务的异常.如果在Timer ...
- unittest之跳过用例(skip) (含如何调用类里面函数相互调取变量的方法)
当测试用例写完后,有些模块有改动时候,会影响到部分用例的执行,这个时候我们希望暂时跳过这些用例. 或者前面某个功能运行失败了,后面的几个用例是依赖于这个功能的用例,如果第一步就失败了,后面的用例也就没 ...
- 【转】在Linux下使用Jmeter执行测试任务
想在Linux下运行jmeter必须先安装jdk,安装步骤如下: (1).下载一个linux可用的jdk包(比如:jdk-6u45-linux-i586.bin), (2).然后将jdk-6u45-l ...
- java代码=========这个代码还是有问题的。不能实现功能呀
有问题的代码: package com.a.b; import javax.swing.*; import java.awt.Color; import java.awt.event.*; impor ...
- java数组求输入平均值
真是学了后面忘了前面,一维数组都忘了 package com.c2; //总结类型转换不对,导致运行报错 //以及没有new,导致空指针异常 //引入流. import java.io.*; publ ...
- 洛谷 P3302 [SDOI2013]森林 Lebal:主席树 + 启发式合并 + LCA
题目描述 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有M条边. 小Z希望执行T个操作,操作有两类: Q x y k查询点x到点y路径上所有的权值中,第k小的权 ...
- 1039 Course List for Student
题意:给出K门课程(编号1~K)以及报名该课程的学生,然后有N个学生查询,对于每一个查询,输出该学生所报的相关课程编号,且要求编号按增序输出. 思路:题目不难,解析略.(本来用map直接映射,用STL ...
- Laravel5 cookie和session设置 Cookie::queue()自动添加
Cookies Laravel会加密所有已创建的cookie信息,并附加上授权码,当客户端擅自修改cookie信息时,该cookie将被废弃,从而保证安全性. 获取一个指定的cookie值 $valu ...
- C Primer Plus学习笔记(十三)- 结构和其他数据形式
建立结构声明 结构声明(structure declaration)描述了一个结构的组织布局 struct book { char title[MAXTITL]; char author[MAXAUT ...
- 谈谈contentWindow 和contentDocument以及 iframe
1,contentWindow:是用来获取子窗口的window对象的,它兼容各大浏览器,用法如下 document.getElementById("iframeId").conte ...