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+贪心)的更多相关文章

  1. POJ 2057 The Lost Home 树形dp 难度:2

    The Lost House Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 2203   Accepted: 906 Des ...

  2. 【bzoj4027】[HEOI2015]兔子与樱花 树形dp+贪心

    题目描述 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接,我们可以把它 ...

  3. POJ 3140.Contestants Division 基础树形dp

    Contestants Division Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10704   Accepted:  ...

  4. POJ:2342-Anniversary party(树形dp入门题目)

    传送门:http://poj.org/problem?id=2342 Anniversary party Time Limit: 1000MS Memory Limit: 65536K Descrip ...

  5. [BZOJ1596] [Usaco2008 Jan]电话网络(树形DP || 贪心)

    传送门 1.树形DP #include <cstdio> #include <cstring> #include <iostream> #define N 1000 ...

  6. 树的点分治 (poj 1741, 1655(树形dp))

    poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子 ...

  7. poj 2342 Anniversary party 简单树形dp

    Anniversary party Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3862   Accepted: 2171 ...

  8. POJ 1155 TELE 背包型树形DP 经典题

    由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送 ...

  9. poj 3140 Contestants Division(树形dp? dfs计数+枚举)

    本文出自   http://blog.csdn.net/shuangde800 ------------------------------------------------------------ ...

  10. POJ 3140 Contestants Division 【树形DP】

    <题目链接> 题目大意:给你一棵树,让你找一条边,使得该边的两个端点所对应的两颗子树权值和相差最小,求最小的权值差. 解题分析: 比较基础的树形DP. #include <cstdi ...

随机推荐

  1. Ionic生成的App安装在手机上后无法联网的解决方案

    在Ionic中使用inappbrowser.themeablebrowser 组件打开网页,刚开始是好的,后来不知添加什么插件,导致了安装在手机上以后没有网络访问权限. 尝试了很多,最后才发现,此时, ...

  2. MySQL 报错 1055

    具体报错 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'exer.student.sid' w ...

  3. PHP no input file specified 三种解决方法

    一.IIS Noinput file specified   (IIS上报的错误) 方法一:改PHP.ini中的doc_root行,打开ini文件注释掉此行,然后重启IIS 方法二: 请修改php.i ...

  4. 【Gym - 100947G】Square Spiral Search

    BUPT 2017 summer training (for 16) #1C 题意 A new computer scientist is trying to develop a new memory ...

  5. python学习日记(函数--装饰器)

    楔子 前提,我有一段代码(一个函数). import time def run_time(): time.sleep(0.1) print('我曾踏足山巅') 需求1:现在,我想计算这段代码的运行时间 ...

  6. Linux 内存清理

    1. Clear PageCache only.sync && echo 1 > /proc/sys/vm/drop_caches2. Clear dentries and in ...

  7. [luogu4005]小Y和地铁【搜索+树状数组】

    传送门:https://www.luogu.org/problemnew/show/P4005 最简单的暴力拿最高的分,二进制爆搜. #include <bits/stdc++.h> #d ...

  8. Atlantis HDU - 1542 (扫描线,线段树)

    扫描线的模板题,先把信息接收,然后排序,记录下上边和下边,然后用一条虚拟的线从下往上扫.如果我扫到的是下边,那么久用线段树在这个区间内加上1,表示这个区间现在是有的,等我扫描到上边的时候在加上-1,把 ...

  9. HDU5909Tree Cutting

    题目大意 给定一颗树,每个点有点权,问对于每个m,有多少个联通块的权值异或和为m. 题解 解法1:可以考虑树形dp,设dp[u][i]表示以u为根的子树中u必须选,联通块权值异或值为i的联通块个数. ...

  10. 20165223《Java程序设计》第七周Java学习总结

    教材学习内容总结 第11章-JDBC与MySQL数据库 要点 MySQL数据库管理系统 连接MySQL数据库 查询操作(基础) 更新.添加.删除(基础) 预处理语句(重点) 通用查询(难点) 事务 笔 ...