百度之星astar-427-problem1

Problem describtion

小H是一个程序员。但是他很喜欢一些新奇的东西。

有一次,他去找物理实验室的朋友玩。他见到了一串非常有意思的粒子。N个粒子排成一排。每一秒中,每一段连续的粒子中会随意有一个爆炸,爆炸后该粒子就消失了,且将原来连续的一段粒子分隔成两段。

小H希望知道所有粒子都爆炸完的期望时间。

Input

         第一行为一个整数T(1 <= T<= 400),表示有T组测试数据;

         每组数据一个正整数N(1<=N<=400),表示一开始的粒子数。

Output

         对于每组数据,输出期望时间(秒)。保留五位小数。

Sample Input
3
1
2
3
 
Sample Output
1.00000
2.00000
2.66667
 
Sample Cl.
对N=3,若第一个爆炸的粒子在旁边,则还需两秒;若第一个爆炸的在中间,则再过一秒即可。故答案为2/3*3+1/3*2=8/3。
27号晚上收到短信,百度邀请你参加百度之星比赛。。。选了problem1,然后,然后没有做完啊!
一看题目,直觉要用动态规划,和给定节点数计算树的数目的问题很像。
定义f(i,k): 长度为的串爆炸时间为k的概率
状态转换:

解释一下,给定长度为i的串,记为L。随机的选择点j作为分裂点,因为是随机选择的,所以选点j的概率为1/i。这样,原串变成了两个字串,记为L1和L2,其长度风别为j-1和i-j。要求算原串爆炸时间为k的概率,有三种情况,第一,L1的串爆时间小于k-1,L2的爆照时间为k-1;第二,L1的串爆时间等于k-1,L2的爆照时间小于k-1;第三,L1和L3的爆照时间都为k-1。使用全概率公式把上面三种情况加起来。

时间空间分析:观察上面的公式,有i,k,j,sum四个变量,时间复杂度为O(N^4),为了降低时间复杂度,可把sum的部分存放起来,这样时间复杂度为O(N^3),空间复杂度为O(N^2).

我的实现

#include <iostream>
#include <fstream>
#include <string>
#define NUPPER 400 
using namespace std;


//  使用动态规划
double aver_bob_time(int N){
    double re;
	float tran[NUPPER + 1][NUPPER + 1];

	float tran_sum[NUPPER + 1][NUPPER + 1];
	
	for(int i = 0; i <= N; i++)
		for(int j = 0; j <= N; j++){
			tran[i][j] = 0;
			tran_sum[i][j] = 0;
			
		}
	for(int i = 0; i <= N; i++)
		for(int j =i; j <= N;j++)
			tran_sum[i][j] = 1;
			
	tran[0][0] = 1;

	for(int i = 1; i <= N; i++){
		for(int k = 1; k <= i; k++){
			for(int j = 1; j <= i; j++){
				int lr = j - 1;
				int ll = i - j;
				if(min(lr,k - 2) >= 0)
					tran[i][k] +=  tran_sum[lr][min(lr,k - 2)] * tran[ll][k - 1];
				if(min(ll,k - 2) >=0 )
					tran[i][k] += tran_sum[ll][min(ll,k - 2)] * tran[lr][k - 1];
				tran[i][k] += tran[lr][k -1] * tran[ll][k -1];
			}	
			tran[i][k] /= i;
			tran_sum[i][k] = tran_sum[i][k - 1] + tran[i][k];
		}
	}
	
	re = 0;
	int tmp = 0;
	for(int i = 1; i <= N; i++){
		re += i * tran[N][i];
	}	
	return re;
}

int main(int argc, char* argv[]){
	int N;
	while(cin >> N){
		cout << aver_bob_time(N) << endl;
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值