Uva10934 详解 装满水的气球(Dropping water balloons)

因为给定气球数后,不同的尝试次数,值是固定的,所以先求出所有解节省时间。

dp(i,j)=dp(i-1,j-1)+1+dp(i,j-1)可以理解为:假设当前在k层,

1.如果该层气球爆炸,则这一层需要消耗一个气球,和一次尝试,所以前面k-1层消耗了i-1个气球和j-1次尝试。

2.如果该层气球不爆炸,则这一层不需要消耗气球,但是需要消耗一次尝试,所以j需要减1。

这类问题可以归结为猜数问题

模型1:给你一个1~N的区间,你最多可以几次猜出X这个数字。假设最终区间左右两边为L和R

f(n)=f(n-1)+f(n-1)+1,这段区间由三部分构成,

1.当你猜测的Y就是所要求的数字X 该段长度为1

2.当你猜测的Y小于X时,你会到(Y,R)这个区间去继续猜测,而(L,Y)这段不再考虑,此时你还有n-1次机会。所以这段长度为f(n-1)

3.当你猜测的Y大于X时,你会到(L,Y)这个区间继续猜测,而(Y,R)这段不再考虑,此时你还有n-1次机会,所以这段长度为f(n-1)

由三种状态之和就是f(n)即f(n)=2f(n-1)+1,

边界条件就是n=1的时候最多可以查询多大区间,长度为1的区间上有两个数,你只要猜其中一个就可以知道另一个了。

举几个例子

f(2)=3  3长度的区间,总共有4个数字(1,2,3,4),你先猜2,然后根据反馈情况来选择继续猜1或者3,

预处理,只要f(n)>=题目所给范围就是要求的n

时间复杂度是o(n)


模型2:还是刚才那个模型在刚才的条件上再加上一个限制询问的到结果中x>y不能超过k次。

很明显如果需要动态规划的化,除了用一个i来记录有几次查询机会,还需要用j来记录还有几次x>y的机会

同样f(i,j)也是由三段组成的

1.直接猜到,长度为1

2.猜到x>y,继续去(y,R)猜,因为猜了一次且为x>y,所以这段长度为f(i-1,j-1),

3.猜到y>x继续去(L,y)猜,因为猜了一次,但不是x>y,所以这段长度为f(i-1,j)

总的长度为f(i,j)=f(i-1,j)+f(i-1,j-1)+1.

边界条件是f(1,0)=0,f(0,1)=0


模型3:被猜数X在1到N之间,你每次询问后,会在你下一提问后才得到上一次的回答。

还是将f(n)分成三段,,因为y‘(第二次询问)在y的左右等价,故设y’在y的左边

1.正好猜到,该区间长度为1,

2.x>y,因为你询问了一个y还浪费了一个y‘,所以f(n-2)

3.y>x,因为你虽然连续询问了两次,但是y’的结果没有浪费f(n-1)

f(n)=f(n-1)+f(n-2)+1;

f(0)=1,f(1)=0


模型4:为模型3和2的结合,被猜数在1到N之间,你每次询问后,会在你下一次提问时猜得到上一次的回答,且不能超过k次x>y

和2一样用f(i,j)表示i次查询,j次x>y最大能够查询的范围.(注意这题不能用上面那个假设y‘法)

1.直接猜到,长度为1

当y’在左边,且x>y长度为f(i-2,j-2)

当y‘在左边,且x<y长度为f(i-1,j)


当y’在右边,且x>y长度为f(i-1,j-1)

当y‘在右边,且x<y长度为f(i-2,j)

因为y’是可以选择的,且要求最优,所以f(i,j)=max(f(i-1,j)+f(i-2,j-2) , f(i-1,j-1) + f(i-2,j) ) +1;

边界条件 f(0,j)=0,f(1,j)=0,f(i,0)=0;


我们现在回到本题,尝试数就是我们的查询书,气球数就是x>y,套用下模型二答案就出来了~~~,因为每次只是查询就好,所以可以先预处理

 

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<algorithm>
#include<iostream>
#include<time.h>
#include<map> 
#include<set>
#include<sstream>
#include<functional>
#include<cassert>
#include<list>
#include<iterator>
#include<utility>
#include <stdexcept>  
#include <sstream>
#include <fstream> 
#include<unordered_map>
#include<unordered_set>
#include<ctype.h>
#include<queue>

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxk = 100 + 5;
const int maxt = 64 + 5;
int k;
long long h;
long long dp[maxk][maxt];

int vs_main()
{
	for (int i = 1; i <= 100; i++)
		for (int j = 1; j <= 64; j++)
			dp[i][j] = dp[i - 1][j - 1] + 1 + dp[i][j - 1];
	while (cin >> k >> h,k||h)
	{
		int ans=INF;
		for (int j = 1; j <= 63; j++)
		{
			if (dp[k][j] >= h)
			{
				ans = j;
				break;
			}
		}
		if (ans == INF)
		{
			cout << "More than 63 trials needed." << endl;
		}
		else
		{
			cout << ans << endl;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jack_jyh/article/details/55672113