POJ - 2057 The Lost House(树形DP+贪心)
https://vjudge.net/problem/POJ-2057
题意
有一只蜗牛爬上某个树枝末睡着之后从树上掉下来,发现后面的"房子"却丢在了树上面,。现在这只蜗牛要求寻找它的房子,它又得从树根开始爬起去找房子。现在要求一条路径使得其找到房子所要爬行的期望距离最小。房子等可能的出现在每个树枝末。某些分叉点会有虫子,会告知上次是否路过此地。
分析
有了虫子的存在,会影响我们遍历这棵树的路径,当虫子给出的信息是N时,就没必要走这个子树。所以问题就是设计一个期望值最小的路径。
设从root结点出发,有两个子树A和B,PA是房子在A子树上的概率,PB同理。那么根据遍历顺序不同,得出以下两个式子:
先A后B的期望:【在A子树上找到房子的总路程】*PA+(【在A子树上没有找到房子的总路程】+【在B子树上找到房子的总路程】)*PB
先B后A的期望:【在B子树上找到房子的总路程】*PB+(【在B子树上没有找到房子的总路程】+【在A子树上找到房子的总路程】)*PA
其中没有找到房子的总路程是固定值,即为遍历整个子树的路程(根据虫子的信息)。
那么答案要求期望最小,需要贪心地遍历子树,上述两个式子一比较,
则变成了【在A子树上没有找到房子的总路程】*PB和【在B子树上没有找到房子的总路程】*PA的比较,于是只用将子树进行排序,然后按照此顺序遍历子树必定是最优的了。
设dp[i][0]表示以i为根的子树找不到房子时要爬行总路程。dp[i][1]表示以i为根的子树在选择好所有分支点的爬行方案后,枚举完房子落在该子树所有叶子节点上的总爬行距离的最小值。
那么有动态方程:
num[x]表示x节点一共有多少个孩子节点
dp[i][0] = sum{ dp[j][0] + 2 } 当i没有毛毛虫且要求j是i的孩子节点, 多出来的2就是连接该孩子节点的边来回的两次
dp[i][0] = 0 当该点有毛毛虫的时候, 原因是因为毛毛虫会告诉我们这点下面没有房子
当一个节点时叶子节点的时候,那么 dp[i][0] = dp[i][1] = 0;
要明确dp[i][1]是表示在遇到分支选择的先后顺序决定后,我们枚举房子在其各个叶子
上的所要爬行的总距离
则dp[i][1] = sum{ (sum{dp[1..j-1][0]+2}+1}*num[j] + dp[j][1]}, 其中j是i的孩子
上面的意思翻译过来就是遍历i的孩子中的j号子树所有叶子节点所
要爬行的最短距离,其值就是: 前面[1, j-1]号子树没有找到节点所爬行的最短距离加上走了的多余的边再加上遍历j
号子树所有叶子节点所爬行的最短距离。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1.0)
//const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = (<<) +;
const int maxm = 1e5 +;
const ll mod = 1e9+;
const double eps = 1e-;
ll qpow(ll a,ll b){ ll res=; for(;b;b>>=,a=a*a%mod) if(b&) res=res*a%mod; return res;} struct ND{
int to,nxt;
}edge[];
int n;
int head[],num[],tot;
bool vis[];
int dp[][];
void addedge(int u,int v){
edge[tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot++;
}
void init(){
ms(head,-);
ms(vis,false);
tot=;
}
int cmp(int a,int b){
return (dp[a][]+)*num[b]<(dp[b][]+)*num[a];
}
void dfs(int u){
int p = head[u];
dp[u][]=dp[u][]=;
num[u]=;
if(p==-){
num[u]++;
}else{
int cnt=,s[];
while(p!=-){
s[cnt++]=edge[p].to;
dfs(edge[p].to);
num[u]+=num[edge[p].to];
if(!vis[u]) dp[u][]+=dp[edge[p].to][]+;
p=edge[p].nxt;
}
sort(s,s+cnt,cmp);
int tmp=;
for(int i=;i<cnt;i++){
dp[u][]+=dp[s[i]][]+(tmp+)*num[s[i]];
tmp+=dp[s[i]][]+;
}
}
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int fa;
char c;
while(~scanf("%d",&n)&&n){
init();
scanf("%d %c",&fa,&c);
for(int i=;i<=n;i++){
scanf("%d %c",&fa,&c);
addedge(fa,i);
if(c=='Y') vis[i]=true;
}
dfs();
printf("%.4f\n",1.0*dp[][]/num[]);
}
return ;
}
POJ - 2057 The Lost House(树形DP+贪心)的更多相关文章
- POJ 2057 The Lost Home 树形dp 难度:2
The Lost House Time Limit: 3000MS Memory Limit: 30000K Total Submissions: 2203 Accepted: 906 Des ...
- 【bzoj4027】[HEOI2015]兔子与樱花 树形dp+贪心
题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...
- POJ 3140.Contestants Division 基础树形dp
Contestants Division Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10704 Accepted: ...
- POJ:2342-Anniversary party(树形dp入门题目)
传送门:http://poj.org/problem?id=2342 Anniversary party Time Limit: 1000MS Memory Limit: 65536K Descrip ...
- [BZOJ1596] [Usaco2008 Jan]电话网络(树形DP || 贪心)
传送门 1.树形DP #include <cstdio> #include <cstring> #include <iostream> #define N 1000 ...
- 树的点分治 (poj 1741, 1655(树形dp))
poj 1655:http://poj.org/problem?id=1655 题意: 给无根树, 找出以一节点为根, 使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子 ...
- poj 2342 Anniversary party 简单树形dp
Anniversary party Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3862 Accepted: 2171 ...
- POJ 1155 TELE 背包型树形DP 经典题
由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送 ...
- poj 3140 Contestants Division(树形dp? dfs计数+枚举)
本文出自 http://blog.csdn.net/shuangde800 ------------------------------------------------------------ ...
- POJ 3140 Contestants Division 【树形DP】
<题目链接> 题目大意:给你一棵树,让你找一条边,使得该边的两个端点所对应的两颗子树权值和相差最小,求最小的权值差. 解题分析: 比较基础的树形DP. #include <cstdi ...
随机推荐
- HAOI2017 简要题解
「HAOI2017」新型城市化 题意 有一个 \(n\) 个点的无向图,其中只有 \(m\) 对点之间没有连边,保证这张图可以被分为至多两个团. 对于 \(m\) 对未连边的点对,判断有哪些点对满足将 ...
- C++ 中 const、volatile、mutable的用法
@2019-01-14 [小记] C++中const.volatile.mutable的用法
- day20
20.01 IO流(IO流概述及分类) 1.IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的类都在IO包中 字节流:字节流可以操作任何数据,计算机中任何数据都 ...
- bzoj3514(LCT+主席树)
题目描述 N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数. 题解 对于一个截止时间来说,越晚的变越好. 所以我们可以维护一颗以边的序号为关键字的最大生成树,然后用主席树维 ...
- tyvj/joyoi 1305 最大子序和
带了一个转化的单调队列裸题. 转化为前缀和相减即可. 有一点需要注意:从0开始入队而不是1,因为要统计第一个. (从网上找的对拍程序,结果别人写错了) /** freopen("in.in& ...
- 洛谷P2824 排序
解:splay + 线段树合并,分裂. 首先有个乱搞做法是外层拿splay维护,有序区间缩成splay上一个节点.内层再开个数据结构支持合并分裂有序集合. 内层我一开始想的是splay,然后就没有复杂 ...
- request 的介绍使用属性
上下文:相当于一个容器,保存了 Flask 程序运行过程中的一些信息. Flask中有两种上下文,请求上下文和应用上下文 请求上下文(request context) 在 flask 中,可以直接在视 ...
- VMware加载vmdk文件
VMware软件文件菜单选择---映射虚拟磁盘选项,如图1所示
- django跨域请求问题
一 同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响.可以说Web是构建在同源策略基础之 ...
- quartz 每天0点5分开始,以后每隔15分钟启动一次,23:50停止
quartz 每天0点5分开始,以后每隔15分钟启动一次,23:50停止,这个表达式怎么写? 5 用quartz做定时器,要求达到这样的效果每天0点5分开始,以后每隔15分钟启动一次,23:50停止不 ...