动态规划 k好数 顽皮猫为你一边讲解一边写代码

上次写了一个关于硬币问题的动态规划,这次我来分析一下k好数问题的动态规划。

题目是这样的:如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数。求L位K进制数中K好数的数目。例如K = 4,L = 2的时候,所有K好数为11、13、20、22、30、31、33 共7个。

我在网上也看了许多博客,现在总结一下这个问题。

首先,我们需要自己来确定两个问题:1.这个k好数是几进制的?2.它有几位?

我们先定义两个int变量:int jinzhi,weishu;//进制和位数。

接下来我们来想想,如何解决这个问题?假如只有1位数,这个数所有的数字都是k好数。即有几进制,就有几个k好数。当然,如果非说0不算,那我们就去掉就好了呀。

如果有两位数,我们只需要关注第二位上面的数字不与第一位上面的数字相邻即可,同理,第三位上的数字不与第二位相邻。。。即:每位上面的数字不与前面一位的数组相邻,且从第一位开始。因此,我们定义一个二位数组dp[i][j]。其中,i表示数字的位数,j表示以j为结尾的数字,整个dp[i][j]就表示i位数以j结尾的k好数的个数。(这里要想清楚!)

首先我们初始化一位数的k好数。在初始化之前,我们需要定义好这个k好数是几进制的?这个数有几位?我们就拿题目中的4进制,2位数字为例。让weishu=2,jinzhi=4;

因此得:int [][] dp = new int[2+1][4];//这里2+1,+1是为了让一维数组的下标值与我们的位数对应,方便看。后面的4不加1是因为,4进制只有0,1,2,3。

接下来初始化1位位数的情况:

for(i=1;i<jinzhi;i++)

{

dp[1][i]=1;//注意,我们让i=0的时候位0了的。看个人怎么理解吧!

}

接下来,我们只需要让后面的一位与前面的一位不相邻即可:

for(i=0;i<=weishu;i++)//最外层循环是让4进制的0,1,2,3这4个数字从最左边一位一步步往右边移动,这里有个<=,等于号要注意!

{

for(j=0;j<zhijin;j++)//这里是<jinzhi  !让每一位从0,1,2,3一次赋值

{

for(int xianglin=0;xianglin<jinzhi;xianglin++)//int xianglin 是用来判断当前的i位上的数字是否与前一位上的数字相邻用的

{

if(j!=xianglin+1&&j!=xianglin-1)

{

dp[i][j]+=dp[i-1][xianglin];

//这段代码就是动态规划的核心了。dp表示的是i位的时候j结尾的k好数个数,它等于第i-1位上面所有结尾不与j相邻的k好数的个数之和。所以用+=。

}

}

}


//上面我们已经求得了所有的dp[i][j];接下来,当我们求i位数j进制的时候就是把i位的时候,结尾为每一位的时候的k好数相加即可!

int sum=0;//先定义一个sum存放这个数字之和。

for(i=0;i<jinzhi;j++)

{

sum+=dp[weishu][i];

}

System.out.println(“位数为”+weishu+"进制为"+jinzhi+“的k好数的个数为:"+sum);//这个sum就是我们要求的k好数的个数了!!

}


源码:

import java.util.Scanner;


public class k
{
public static void main(String [] args)
{
int jinzhi,weishu;//进制,位数
int i,j;
System.out.println("输入  进制数 和   位数");
Scanner in = new Scanner(System.in);
jinzhi = in.nextInt();
weishu=in.nextInt();
int [][] dp = new int[weishu+1][jinzhi];

for(i=1;i<jinzhi;i++)
{
dp[1][i]=1;
}


//if(weishu>=2)
//{
for(i=2;i<=weishu;i++)
{
for(j=0;j<jinzhi;j++)
{
for(int xianglin=0;xianglin<jinzhi;xianglin++)
{
if(j!=xianglin-1&&j!=xianglin+1)
{
dp[i][j]+=dp[i-1][xianglin];
}
}
}
}
//}

int sum=0;
for(i=0;i<jinzhi;i++)
sum+=dp[weishu][i];
System.out.println(sum);
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值