poj2057 The Lost House

题意:

给出一颗有根树,边权均为1;

一个S在根结点上,要找到在某个叶子结点上的它的房子;

有的结点上有w,可以告诉S当前结点的子树上是否有它的房子;

房子在每个叶子结点的概率相等,选择一种最佳的计划,来让S走的期望值最小;

题解:

为了这道题去补了补期望是个啥;

简单来说就是,数学期望值=∑ f[x] * p[x]

f[x]是变量的值,p[x]是变量的概率;

那么,在某种特定的行走计划中,对于某个叶子结点上有房子所需要走的路程,应当是一个定值;

而每个叶子结点的概率都是叶子结点的总数的倒数;

因此,求出一种行走计划,将所有的路程加起来,再除以叶子结点总数,就是题中所求的期望值;

问题现在是找到一种这样的计划,这个问题的子问题无后效性是很显然的;

那么对一个结点的两个儿子,在决策上应当先走那个呢?

先设状态fa[x]表示x的子树上有房子的期望值;

fb[x]表示x的子树上没有房子的期望值;

令x为父结点,y1,y2为子结点,le[x]指x结点的子树上的叶子数;

那么先走y1的答案就是:

fa[x]=fa[y1]+1*le[y1]+(fb[y1]+2+1)*le[y2]+fa[y2];

// 当在y1子树上答案是fa[y1]+le[y1]因为除了在子树上以外,还有从父亲x走到y1的一步;

//      而在y2上应该是计算了之前子树的(fb[x]+1)*le[y2]表示多走的路,然后再加上fa[y2];

fb[x]=fb[y1]+2+fb[y2]+2;

先走y2的答案是:

fa[x]=fa[y2]+1*le[y2]+(fb[y2]+2+1)*le[y1]+fa[y1];

fb[x]=fb[y2]+2+fb[y1]+2;

可见,fb是不受先走后走的影响的,而将两个决策做比较,令y1优于y2,化简可得;

(fb[y1]+2)*le[y2]<(fb[y2]+2)*le[y1];

于是就可以用这个规律来判断,并且在多个子结点也可以这么搞,以这个排序维护fa,fb就可以了;

结点上有w的时候需要一点特判,就是S到达时立刻可以知道这里有没有房子,所以这里的fb就是0;

然后输出fa[root]/le[root]就可以了,实际上只需要最后输出转化浮点型即可;

代码:

#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1001
using namespace std;
vector<int>to[N];
int le[N],fa[N],fb[N];
bool is[N];
char str[10];
void init(int n)
{
	for(int i=1;i<=n;i++)	to[i].clear();
	memset(fa,0,sizeof(fa));
	memset(fb,0,sizeof(fb));
	memset(le,0,sizeof(le));
	memset(is,0,sizeof(is));
}
int cmp(int a,int b)
{
	return (fb[a]+2)*le[b]<(fb[b]+2)*le[a];
}
void dfs(int x)
{
	le[x]=0;
	int i,y,cnt=0;
	int son[9];
	for(i=0;i<to[x].size();i++)
	{
		y=to[x][i];
		dfs(y);
		le[x]+=le[y];
		son[++cnt]=y;
	}
	sort(son+1,son+1+cnt,cmp);
	for(i=1;i<=cnt;i++)
	{
		fa[x]+=(fb[x]+1)*le[son[i]]+fa[son[i]];
		fb[x]+=fb[son[i]]+2;
	}
	if(!le[x])
		le[x]=1;
	if(is[x])
		fb[x]=0;
}
int main()
{
	int n,m,i,j,k,x,y,root;
	while(scanf("%d",&n)&&n)
	{
		init(n);
		for(i=1;i<=n;i++)
		{
			scanf("%d%s",&x,str);
			if(x!=-1)
				to[x].push_back(i);
			else
				root=i;
			if(str[0]=='Y')
				is[i]=1;
		}
		dfs(root);
		printf("%.4lf\n",((double)fa[root])/le[root]);
	}
	return 0;
}
时间: 2024-11-07 07:23:52

poj2057 The Lost House的相关文章

poj2057 The Lost Home

The Lost House Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 2203   Accepted: 906 Description One day a snail climbed up to a big tree and finally came to the end of a branch. What a different feeling to look down from such a high plac

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

ACM算法总结及刷题参考

参考:http://bbs.byr.cn/#!article/ACM_ICPC/11777 OJ上的一些水题(可用来练手和增加自信)(poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,poj2255,poj3094) 初期: 一.基本算法: (1)枚举. (poj1753,poj2965)    (2)贪心(poj1328,poj2109,poj2586)    (3)递归和分治法.     (4)递推.     (5)构造法.(po

POJ题目推荐(转载)

POJ推荐50题1.标记“难”和“稍难”的题目可以看看,思考一下,不做要求,当然有能力的同学可以直接切掉.2.标记为A and B的题目是比较相似的题目,建议大家两个一起做,可以对比总结,且二者算作一个题目.3.列表中大约有70个题目.大家选做其中的50道,且每类题目有最低数量限制.4.这里不少题目在BUPT ACM FTP上面都有代码,请大家合理利用资源.5.50个题目要求每个题目都要写总结,养成良好的习惯.6.这个列表的目的在于让大家对各个方面的算法有个了解,也许要求有些苛刻,教条,请大家谅

树形 DP 总结

本文转自:http://blog.csdn.net/angon823/article/details/52334548 介绍 1.什么是树型动态规划 顾名思义,树型动态规划就是在"树"的数据结构上的动态规划,平时作的动态规划都是线性的或者是建立在图上的,线性的动态规划有二种方向既向前和向后,相应的线性的动态规划有二种方法既顺推与逆推,而树型动态规划是建立在树上的,所以也相应的有二个方向: 1.叶->根:在回溯的时候从叶子节点往上更新信息 2.根 - >叶:往往是在从叶往根d

POJ题目分类

初期: 一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:     (1)图的深度优先遍历和广度优先遍历.     (2)最短路径算法(dijkstra,bellman-ford,floyd,he

嗷嗷嗷,kuangbin大大博客上拉的题

正在学(learning),未学(waiting),已学(cut  vovering) 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:     (1)图的深度优先遍历和广度优先遍历.  

转:转一个搞ACM需要的掌握的算法. .

要注意,ACM的竞赛性强,因此自己应该和自己的实际应用联系起来.  适合自己的才是好的,有的人不适合搞算法,喜欢系统架构,因此不要看到别人什么就眼红,  发挥自己的长处,这才是重要的. 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,  因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打  出来.  1.最短路(Floyd.Dijstra,BellmanFord)  2.最小生成树(先写个prim,kruscal要用并查集,不好写)

算法初学者指南

摘自网络,对于这个训练计划,我只能膜拜,~ 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码, 因为太常用,所以要练到写时不用想,10-15 分钟内打完,甚至关掉显示器都可以把程序打 出来. 1.最短路(Floyd.Dijstra,BellmanFord) 2. 最小生成树(先写个prim,kruscal要用并查集,不好写) 3.大数(高精度)加减乘除 4.二分查找. (代码可在五行以内) 5.叉乘.判线段相交.然后写个凸包. 6.BFS.DFS,同时熟练hash表(