这是一道超小型dp题目,写的很快,索性写个报告
题目的意思是,一个猜价格的游戏。参与者有G次猜价格的机会,而且有L条命
每猜一次,用一次猜的机会,主持人会告诉你这个答案大了,小了还是猜中了。每次猜的价格高于真正的价格,丢一条命。G或者L用光而没有猜到,就输了。
问你,如果给定G和L,那么用一种保险的策略去猜,可以保证当这个价格在1到N之间时,肯定可以猜出正确价格。
写程序求这个N
G和L都不大于30,规模很小。
这题目一看基本就属于dp了,想一下怎么归纳到子问题就行了。
首先考虑集中情况
1.当L等于0的时候,那么一旦你猜多了,立刻就输了,所以只能1,2,3,4,这样往上猜,也就是输dp[i][0]一定等于i
2.当G和L相等时,也就是不用考虑L,你不可能出现G没用完L就用完的情况。那么有i次机会猜一个数,这个相当于过去说诸葛亮那个问十次大小猜数字的问题。dp[i][j] = 2^i - 1, 这个结论很简单
3.当以上两种情况都不符合时,这种需要稍微考虑一下。我们只考虑这游戏的第一个数字猜什么,后面的都是一样的,递归的道理。那么第一个数字猜什么呢,假设我才的是X,那么我们得保证,如果X比实际结果大,我失去了一个G和一个L,利用G-1和L-1,我可以把1~X-1猜的完。如果X比这个大的话,这个策略就有风险。所以,X = dp[g-1][l-1] + 1. 你利用G-1和L-1可以确保猜出的最大值再加1,就是你第一次猜的数字。那么如果你猜大了,损失了一个G和一个L,依然猜得出。如果猜小了,你还有G-1和L,所以还可以再覆盖dp[g-1][l]这么大的区域。这种情况时,dp[i][j] = dp[i-1][j-1] + 1 + dp[i-1][j],稍微想一下很容易想通的
这题是多case,所以预处理直接把所有值求出来,相当于打表。读哪个数据,直接输出哪个结果。0ms无压力
附代码
int dp[32][32];
int g,l;
int main()
{
freopen("in.txt","r",stdin);
MSET(dp);
for (int i = 1; i <=30; i++)
{
for (int j = 0; j <= i; j++)
{
if (j == 0)
{
dp[i][j] = i;
}
else if (i == j)
{
dp[i][j] = pow((float)2,(float)i) - 1;
}
else
{
dp[i][j] = dp[i-1][j-1] + dp[i-1][j] + 1;
}
}
}
int id = 0;
int m;
while (cin>>g>>l&&(g||l))
{
printf("Case %d: %d\n",++id,dp[g][l]);
}
return 0;
}