整数划分问题

把100拆分成4个整数之和,有多少种拆分方法。注意1+2+3+94和94+1+2+3只能算一种。

一看到这题,觉得很容易,以为用暴力求解就可以了,但是后面的限制条件不知道怎么写,硬着头皮写了些限制条件,但是算出来的结果非常大,感觉根本不是答案。

在网上到处搜索,看到这种整数划分问题可以用动态规划解决,于是尝试去理解这方面的动态规划。但是看不懂,只好求助班里的大神,大神一直很忙,过了两天,给我发了

视频,六百多兆的视频,大神说,打字说不清,于是发个视频,感动cry,这个太麻烦,没有人给我讲,所以非常谢谢大神。


主要的代码部分是dp[n][k]=dp[n-1][k-1]+dp[n-k][k]


即把dp[i][j]分成两个主要的部分:

第一部分:n份中,至少有一份包含1,就减去这个1,把1作为单独的一份,于是本来要分成k份的,现在减去1份,变成k-1份,于是有dp[n-1][k-1]


第二部分:n份中,不包含1的分法,不包含1,就把每一份都减去1,分成k份,就减去k个1,于是有n-k,于是有dp[n-k][k-1]


把这两个子状态相加即可。我看的时候,还有个疑问,这个1到底指的是什么?为什么要按照包含1和不包含1来划分?在学习递归的时候,也有类似的问题,

那时候看一个视频,里面的老师说,假设我们已经把所有的划分都分好了,现在把1当成一个特殊的数字,那么所有的划分就会满足包含1的和不包含1的来划分。

还是似懂非懂,不过就这样理解吧。

java代码:

import java.util.Scanner;
public class Main {


public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int k = input.nextInt();

int[][] num = new int[n+1][n+1];

int i, j;
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++){
num[i][j] = 0;
}
}

for(i=1; i<=n; i++)
{
for(j=1;j<=n;j++){
if(i < j)
{
num[i][j] = 0;
}
if(i == j)
{
num[i][j] = 1;
}
if(i > j)
{
num[i][j] = num[i-1][j-1] + num[i-j][j];
}
}
}

System.out.println(num[n][k]);
}
}


c++代码:

#include <iostream>  
#include <cstdio>  
#include <queue>  
#include <vector>  
#include <map>  
  
using namespace std;  
  
int main()  
{  
    int n, k;  
    while( cin >> n >> k )  
    {  
        int num[n+1][n+1];               
        
        int i, j;                            
        for( i=0; i<=n; i++ )  
        {  
            for( j=0; j<=n; j++ )  
            {  
                num[i][j] = 0;  
            }  
        }  
                                     
        for( i=1; i<=n; i++)  
        {  
            for( j=1; j<=n; j++)  
            {  
                if( i < j )  
                {  
                    num[i][j] = 0;  
                   
                }  
                if( i == j )  
                {  
                    num[i][j] = 1;  
                    
                }  
                if( i > j )  
                {  
                    num[i][j] = num[i-1][j-1] + num[i-j][j];  
                }  
            }  
        }  
        
        cout << num[n][k] <<endl;  
    return 0;  
   }
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值