//动态规划,迭代
//思路:循环遍历所有情况
//迭代每次分两种情况,要么打酒要么看花分两种考虑
//用a[0][0][2]=1标记为真+迭代
//从而实现在所有情况中给最终结果
//增加有效值.
//迭代时注意设置条件避免输入非法数据
//
#include <stdio.h>
#include <stdlib.h>
#define mod 1000000007
int main(int argc, char *argv[])
{
//0斗没有意义,因为最后要看花,不可能有0斗遇店
int n,m,i,j,p;//n酒m花
int a[101][101][101];//根据题设最大来设大小,用三维数组
a[0][0][2]=1;//初始状态
//如果在迭代中往前推推不到这个数组的,就一定是非法情况
//自然数组最终结果为0
//设1时相当于考虑开始时酒有两斗的情况,只有开始遵循这点才能算一种可能,相当于标记
scanf("%d%d",&n,&m);
//题范围为100,三个循环10^(2*3)=10^6够用
for(i=0;i<=n;i++)//打酒
//打多少次酒情况的遍历
{
// for(int j=0;i<=m;j++)//你看又是条件青光眼,真的6
for(int j=0;j<=m;j++)//花
//看多少次花情况的遍历
{
for(p=0;p<=m;p++)//酒量//循环上限是m是因为酒量和看花次数要相等
//酒量为多少次情况的遍历
{
//打酒还是看花每次循环都分两个分支讨论
//合法的自然会返回给a[n][m][0]真值
//不合法自然返回0。
if(p%2==0&&p>0&&i>0)//打酒
//因为还需要讨论不打酒的情况,即i=0时
//0斗就不可能再加酒了
{
// a[i][j][p]=(a[i][j][p]%mod)+(a[i-1][j][p/2]%mod);
a[i][j][p]+=(a[i-1][j][p/2]%mod);
//这一次情况 上一次
//迭代
}
if(j>0)//看花
//1开始表示开始看花
{
// a[i][j][p]=(a[i][j][p]%mod)+(a[i][j-1][p+1]%mod);
a[i][j][p]+=(a[i][j-1][p+1]%mod);
//这次情况 上次的
//可以直接写+=,因为每次迭代最新的情况即空数组,
//根本就不存在数据溢出,因此对空数组没必要取模,只用
//对前面的数组取模即可
//看一次花少一斗,符合逻辑连接之前的数组,相当于一条线,就为一种情况,
//要清楚因为循环是递增的,所以左边是后面的情况,右边是前面的情况
//如a[0][0][2],那么它看花就是a[0][1][1]
//等于1是标记也是计数,只有一直传下来到达最终的a[n][m][0]就统计为一种情况
//等于0说明开始时不是两斗酒
//最典型的就是p%2==0,假如后面的数组为[1][0][3],推前面为[0][0][1.5]
//这是不存在的,所以要舍弃,其他同理
//迭代思想每次都要从前面找答案,随着循环变大才能推出后面的结果
//因此正常思路也一定是左边是当前最大的结果,右边是前面的结果!
//想获得最终的答案,那都是要在前面结果的基础才能得出的!
//满足条件,才进行此次情况的访问,计算这一次的结果,
//因此放在左边,
//而要算出,就要使用迭代,就是同样要找前面的结果
}
}
}
}
printf("%d",a[n][m][0]);
//循环遵循从简单到复杂,优先循环最简单的情况最佳
//多重循环就是为了讨论完所有情况,最后回到a[n][m][0]时
//就返回之前积累的所有的情况。
//遍历所有可能,无脑循环查找.不必担心合不合法,不合法自然只会+0
//a[0][0][2]开始的迭代就已经是合法的前提了!
//a[n][m][0]表示他一共遇到店 N次, 遇到花 M次。正好把酒喝光了。
//按照题设操作
return 0;
}
蓝桥杯2022年第十三届省赛真题-李白打酒加强版(超详细解析)
于 2023-02-26 11:24:23 首次发布