树形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 ...
随机推荐
- flask之redis
redis 连接需要host port passwod Hash:key-fields-value(做缓存)相当于一个key对于一个map,map中还有key-valueList:有顺序可重复(处理不 ...
- composer安装特别慢的解决方案
在项目开发的时候 有许多新的依赖要按照 就需要用到composer 但是由于国内安装下载速度贼慢(国外的网站连接速度太慢,并且随时可能被墙) 安装一个excel扩展(composer require ...
- 阿里云ubuntu 创建svn服务器
1.SubVersion服务安装 sudo apt-get install subversion sudo apt-get install libapache2-svn 2.服务器配置 2.1相关用户 ...
- 【转】使用Jmeter针对ActiveMQ JMS Point To Point压力测试
准备工作 针对JMS类型的Sampler,需要额外的jar包(这里用的是apache ActiveMQ,将下载的AMQ apache-activemq-5.5.0根目录下的activemq-all-5 ...
- Effective java笔记2--创建于销毁对象
一.创建对象的两种方式 1.提供公有的构造器. 2.提供一个返回类实例的静态方法. 二.使用静态方法创建对象 优势: 1.静态工厂方法的一个好处是,与构造函数不同,静态工厂方法具有名字.产生的客户端代 ...
- python ftp 上传
#!/usr/bin/python # -*-coding:utf- -*- from ftplib import FTP def ftpconnect(host,username,password) ...
- Bind("入库日期", "{0:yyyy-MM-dd}") 关于asp.net格式化数据库日期字符串
Bind("入库日期", "{0:yyyy-MM-dd}") 关于asp.net格式化数据库日期字符串,删除多余的000:0:00
- 记录MongoDB常用查询
{$and:[{"}}]} // flag不等于1 也不等于0 {$or:[{"flag" :{ $ne:"1"}},{"flag" ...
- C51串口的SCON寄存器及工作…
原文地址:C51串口的SCON寄存器及工作方式作者:batistar 一,串行口控制寄存器SCON 它用于定义串行口的工作方式及实施接收和发送控制.字节地址为98H,其各位定义如下表: D7 D6 D ...
- Laravel 5.3 auth中间件底层实现详解(转)
1. 注册认证中间件, 在文件 app/Http/Kernel.php 内完成: protected $routeMiddleware = [ 'auth' => \Illuminate\Aut ...