洛谷P1244 青蛙过河(dp,递推)
作者:互联网
题目描述
有一条河,左边一个石墩(A区)上有编号为1,2,3,4,…,n的n只青蛙,河中有k个荷叶(C区),还有h个石墩(D区),右边有一个石墩(B区),如下图所示。n只青蛙要过河(从左岸石墩A到右岸石墩B),规则为:
(1)石墩上可以承受任意多只青蛙,荷叶只能承受一只青蛙(不论大小);
(2)青蛙可以:A→B(表示可以从A跳到B,下同),A→C,A→D,C→B,D→B,D→C,C→D;
(3)当一个石墩上有多只青蛙时,则上面的青蛙只能跳到比它大1号的青蛙上面。
你的任务是对于给出的h,k,计算并输出最多能有多少只青蛙可以根据以上规则顺利过河?
输入格式
两个整数h,k
输出格式
一个整数,表示最多能有多少只青蛙可以根据以上规则顺利过河。
输入输出样例
输入 #1复制
2 3
输出 #1复制
16
题意: 就是A,B是两个汉诺塔,中间有n个可以放无限多青蛙的汉诺塔,m个只能放一个青蛙的汉诺塔,而且B只能放,不能拿。问A上最多装多少个青蛙,使得全部转移到B上去。
思路: 递推解法不写了,m*(1<<n)几行代码没了。
- 多见的解法是递推,但也可以看出是一个dp,只不过两个子状态都是最优的,所以可以选择一个子状态递推下去,直接得到结果。就是m * (1 << n)。
- 定义状态dp(i,j)为放了i个石头j个荷叶的结果,显然dp[0][0] = 1。
- 初始状态:很明显dp(0,j) = j + 1。相当于A中放了第j+1个青蛙,j个荷叶各放了一个青蛙,刚好能全部装入B中。而dp(i,0):只有石头的时候,假设一个石头,要让尽可能多的青蛙先到中间的一个石头,再让A中尽可能多的青蛙到B石头,得到f[1][0] = f[0][0] + f[0][0]。对于f[2][0]也是如此,f[2][0] = f[1][0] + f[1][0]。于是f[n][0] = f[n - 1] * 2。
- 状态转移。荷叶对状态只有乘积的影响。可以看做先初次全部加入,最后一步一步加石头,因此荷叶的影响就是数量+1作为的一个因子。两个子状态就是一个乘以2,一个改变因子。
- 两个子状态都是最优的,都可以按照一个递推得到结果。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
int dp[1005][1005];
int main()
{
int n,m;scanf("%d%d",&n,&m);//n个石头 m个荷叶
dp[0][0] = 1;
for(int i = 1;i <= n;i++)
{
dp[i][0] = dp[i - 1][0] * 2;
for(int j = 1;j <= m;j++)
{
dp[0][j] = j + 1;
dp[i][j] = max(dp[i - 1][j] * 2,dp[i][j - 1] / j * (j + 1));
}
}
printf("%d\n",dp[n][m]);
return 0;
}
标签:洛谷,青蛙,荷叶,石墩,P1244,include,递推,dp 来源: https://blog.csdn.net/tomjobs/article/details/100596603