| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
借助大牛的记忆搜索(DP),改了改代码,不过我把算法和过程分析的很清楚了,可以满足不清楚的童鞋了/*
算法思想:
题目大意:每个人允许猜 G 次,有 L 生命线。
猜低或猜高了,耗费一次猜得机会,猜高了,还会浪费一生命线。
// DP(动态规划)问题,一般用递推来做,不用递归,递归太费时间
// 先从搜索考虑。设f(guss,life)表示有guss次机会,life条生命线时可以猜到的最大价格范围N。
// 那么,f(guss,life)应该由3种情况组成组成:
1.猜低了,用剩下的机会还能猜出f(guss-1,life)范围的价格;
2.猜得正好,1次猜出价格
3.猜高了,用剩下的机会还能猜出f(guss-1,life-1)范围的价格。
拼起来,就有f(guss,life) = f(guss-1,life) + f(guss-1,life-1) + 1。
// 然后考虑一下边界情况:当g=0时,游戏结束了,所以f(0,life)=0;
// 当life=0时,价格不能再猜高了,只能往下再摸索guss次,所以f(guss,0)=guss。
// 这样就可以用搜索来解决这个题了。再转成记忆化搜索就行了。
// 也可以观察出阶段,自底向上推。
*/
for example:
其中guss代表行,life代表列
执行完for循环的数组:
由于数组太大,我们暂时只给出4列:
当执行完for循环后,dp二维数组状态为:
0 0 0 0 -------------------f(0,life) = 0,符合这个规律,而第一列符合f(guss,0) = guss
1 1 1 1
2 3 3 3
3 6 7 7
f(3,0) = 3;
f(3,1) = 6;
比如:
f(3,1) = f(2,1) + f(2,0) + 1
= [f(1,1)+f(1,0)+1] + 2 + 1
= [[f(0,1)+f(0,0)+1] + 1 + 1] + 2 + 1
= 0 + 0 + 1 + 1 + 1 + 2 +1
= 6
--------------------------code--------------------
#include"stdio.h"
#include <string.h>
int main(void)
{
int dp[31][31];
int n_guss,n_life,i,j,temp = 1;
memset(dp,0,sizeof(dp));
for(i = 0;i < 31;++i)
{
dp[ i ][ 0 ] = i;//f(guss,0)=guss,把0个life的行赋值为0,1,2....
}
for(i = 1;i < 31;++i)
{
for(j = 1;j <= i;++j)
{
dp[i ][j] = dp[i - 1][j] + dp[i - 1][j - 1] + 1;
}
while(j < 31)
{
dp[i][j] = dp[i][i];
j++;
}
}
while(scanf("%d %d",&n_guss,&n_life),(n_guss != 0)|| (n_life != 0))
{
printf("Case %d: %d\n",temp++,dp[n_guss][n_life]);
}
return 0;
}
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator