HDOJ 5781 ATM Mechine

最近练习概率DP和计算的还是有用的啊,知道经典思路是什么了

题目链接:HDOJ5781


说说题意吧:有一本存折,忘记了有多少钱,只记得钱数不超过K

现在有M次猜测的机会,必须要确定存折中有多少钱!

确定一个词,理解好了,这个题就好了。这样理解确定:

如果现在钱数不超过T,取一块钱都取不出来了,那么就确定存折里面没有钱了

如果现在钱数为1,取1块钱取出来了,那么就确定存折里面没有钱了(因为所有钱都已经取出来了)

确定一词,是用来确定边界情况的


所以,这个题的方法就是枚举:枚举所有的可能猜测的值(从1枚举到K),当然,有的取得出来,有的取不出来

日常概率的经典做法就是分类:

dp【i】【j】为现在钱数不超过i,还有j次猜测的情况下的期望

如果假设当前情况下钱数我要取K,那么有两种情况:

取得出来:说明钱数上限比K大,那么是由dp【i-k】【j】过来的,概率是(i-k+1)/(i+1),分子是说k,k+1,k+2,……i,都符合,分母是说0,1,2,……i

取不出来:说明钱数上限不足K,那么上限为K-1(还是不确定有多少钱),用过了一次猜测的机会,概率是k/(i+1),那么是由dp【k-1】【j-1】过来的

k是多少呢?不知道,所以需要枚举


这样看,i,j,k三个变量,三重循环,都是需要枚举的,复杂度是O(K^2*W),会超时

那么,想想,W是不需要那么搞的,因为最好的方法是二分,就可以减去一半的枚举量,也就是说:

最多的枚举次数是:O(logK),K最大是2000,那么j最大是12咯

所以可以用上面的方法打表,而且减小时间复杂度


#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;

const int maxw=12;
const int mod=1e9+7;
double dp[2333][15];
const double eps=1e-8;
const double INF=1e9;
int main(){
	//freopen("input.txt","r",stdin);
	for(int i=0;i<=2000;i++)
		for(int j=0;j<=maxw;j++){
			dp[i][j]=INF;
			if (i==0) dp[i][j]=0;
			else if (j>0){
				for(int k=1;k<=i;k++)
					dp[i][j]=min(dp[i][j],(i+1-k)*1.0/(i+1)*dp[i-k][j]+k*1.0/(i+1)*dp[k-1][j-1]);
				dp[i][j]+=1;
			}
		}
	int k,w;
	while(scanf("%d%d",&k,&w)!=EOF){
		w=min(w,maxw);
		printf("%.6lf\n",dp[k][w]);
	}
	return 0;
}


全部评论

相关推荐

2025-12-30 16:42
同济大学 C++
仁狂躁使者:哎呀,不用担心,我当时配环境配了两天,项目捋不清就问问导师能不能用ai,慢慢就清了,会好起来的
点赞 评论 收藏
分享
02-14 12:40
门头沟学院 Java
程序员花海:1.面试要求必须Java笔试不一定 2.难度对等秋招 远超于日常实习是因为同一批次且转正很多 竞争压力大 3.第一个加点指标,上线了就把接口性能加上去 使用本地缓存这个不算亮点 只是技术选型,要把为什么采用这个和背后的思考写出来而不是单纯堆叠技术没意义 4.八股要一直看 很容易忘记 5.拼团交易这个老问题 堆积技术 另外建议你把奖项合并到教育背景 没必要拆出来放最后
我的简历长这样
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务