整数划分问题
2017-08-08 14:19
239 查看
把100拆分成4个整数之和,有多少种拆分方法。注意1+2+3+94和94+1+2+3只能算一种。
一看到这题,觉得很容易,以为用暴力求解就可以了,但是后面的限制条件不知道怎么写,硬着头皮写了些限制条件,但是算出来的结果非常大,感觉根本不是答案。
在网上到处搜索,看到这种整数划分问题可以用动态规划解决,于是尝试去理解这方面的动态规划。但是看不懂,只好求助班里的大神,大神一直很忙,过了两天,给我发了
视频,六百多兆的视频,大神说,打字说不清,于是发个视频,感动cry,这个太麻烦,没有人给我讲,所以非常谢谢大神。
主要的代码部分是dp
[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
[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
[k] <<endl;
return 0;
}
}
一看到这题,觉得很容易,以为用暴力求解就可以了,但是后面的限制条件不知道怎么写,硬着头皮写了些限制条件,但是算出来的结果非常大,感觉根本不是答案。
在网上到处搜索,看到这种整数划分问题可以用动态规划解决,于是尝试去理解这方面的动态规划。但是看不懂,只好求助班里的大神,大神一直很忙,过了两天,给我发了
视频,六百多兆的视频,大神说,打字说不清,于是发个视频,感动cry,这个太麻烦,没有人给我讲,所以非常谢谢大神。
主要的代码部分是dp
[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
[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
[k] <<endl;
return 0;
}
}
相关文章推荐
- NYOJ 279 队花的烦恼二和NYOJ 176 整数划分(二)【dp问题或递归】
- 整数划分问题 DP
- 整数划分问题
- 算法设计--整数划分问题
- 整数划分问题 【经典DP】
- 整数划分问题(数学)
- OpenJ_Bailian - 4117简单的整数划分问题-递归&动态规划
- 有序的整数划分,青蛙跳台阶问题 MATLAB
- 整数划分问题
- 整数划分问题
- C/C++ 整数划分问题
- 0804 OpenJ#7215 简单的整数划分问题
- 递归---整数划分问题
- 整数划分问题
- 递归 放苹果问题和整数划分问题
- 正整数n的划分问题
- 递归算法--写实例----阶乘问题---整数划分问题
- 整数划分问题算法分析与实现(递归)
- dp-整数划分问题
- 整数划分和放苹果问题