import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while((line = br.readLine()) != null) {
String[] strArr = line.split(" ");
int n = Integer.parseInt(strArr[0]), m = Integer.parseInt(strArr[1]);
// 背包问题变体 dp[i][j]表示从1~i中组合成数字j的组合数
int[][] dp = new int[n + 1][m + 1];
for(int i = 0; i <= n; i++) dp[i][0] = 1;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(i <= j)
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - i];
else
dp[i][j] = dp[i - 1][j];
}
}
System.out.println(dp[n][m]);
}
}
} |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| 3 | 1 | 1 | 2 | 1 | 1 | 1 | 0 | 0 |
| 4 | 1 | 1 | 2 | 2 | 2 | 2 | 1 | 1 |
| 5 | 1 | 1 | 2 | 2 | 3 | 3 | 2 | 3 |
| 6 | 1 | 1 | 2 | 2 | 3 | 4 | 3 | 4 |
# 动态规划的解法, 每次考虑是否加入这个数字, # 行表示最大的n, 列表示sum,行和列均从0 开始 # 数组中的值为count,初始化数组时,第一列全为1, 表示sum为0时, 对所有的n结果均为1n, m = list(map(int, input().strip().split())) dp = [[1 if i == 0 else 0 for i in range(m+1)] for j in range(n+1)] for row in range(1, n+1): for col in range(1, m+1): if col - row < 0: dp[row][col] = dp [row-1][col] else: dp[row][col] = dp[row - 1][col] + dp[row-1][col-row] print(dp[n][m])
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int f[121][121]={0};
for (int i=0;i<=n;i++)
{
f[i][0]=1;
}
for (int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j>=i)
{
f[i][j]=f[i-1][j-i]+f[i-1][j];
}
else
{
f[i][j]=f[i-1][j];
}
}
}
cout<<f[n][m];
}
#include<iostream>
#include<vector>
using namespace std;
int n,m,x;
void backing(int start,int sum){
if(sum==m){
++x;
return;
}
for(int i=start;i<=n && sum+i<=m;i++){
sum+=i;
backing(i+1,sum);
sum-=i;
}
}
int main()
{
cin>>n>>m;
backing(1,0);
cout<<x;
} 这题显然是有 dp 做法的,但是一看数据范围这么小,果断搜索了。
/**
* Author: yurzhang
* Date: 2020/04/22
*
* Natsuiro Matsuri
*/
%:pragma GCC optimize("Ofast,inline,unroll-loops")
#include <cstdio>
int n,m,ans;
int now;
void dfs(int last) {
for(int i=last+1;i<=n;++i) {
if(now+i==m) ++ans;
if(now+i>=m) break;
now+=i; dfs(i); now-=i;
}
}
int main() {
scanf("%d%d",&n,&m);
dfs(0);
printf("%d",ans);
return 0;
} 顺便,题目描述最好说清楚不能选重复的数,虽然看样例可以得知这个信息。
import java.util.*;
public class Main {
private static final int MAX = 125;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
int[]dp = new int[MAX];
dp[0] = 1;
for (int i=1; i<=n; i++) {
for (int j=m; j>=i; j--) {
dp[j] += dp[j - i];
}
}
System.out.println(dp[m]);
}
}
#include <iostream> #include<vector> using namespace std; int res=0; void solve(int n, int m, vector<int>& s, int num) { if (m == 0) res++; for (int i = num; i <= n&&i <= m; i++) { s.push_back(i); solve(n, m - i, s, i + 1); s.pop_back(); } } int main() { int n, m; while (cin >> n >> m) { vector<int> s; solve(n, m, s, 1); cout<<res<<endl; res=0; } }
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
public class NumberSum {
public static void main(String[] args) {
Scanner in = new Scanner(
new BufferedReader(new InputStreamReader(System.in)));
while (in.hasNext()) {
int n = in.nextInt();
int sum = in.nextInt();
int[] a = new int[n];
for (int i = 1; i <= n; i++) {
a[i - 1] = i;
}
long[] dp = new long[sum + 1];
dp[0] = 1;
//只能选择一次,所以01背包,从大到小
for (int i = 0; i < n; i++) {
for (int j = sum; j >= a[i]; j--) {
dp[j] += dp[j - a[i]];
}
}
System.out.println(dp[sum]);
}
in.close();
}
}
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
int n = in.nextInt();
int m = in.nextInt();
System.out.println(countOfsum(n, m, 1));
}
public static int countOfsum(int n, int m, int min) {
if (m == 0)return 1;
int count = 0;
for (int i = min; i <= n && i <= m; i++) {
count += countOfsum(n, m - i, i + 1);
}
return count;
}
} #include <stdio.h>
int main(int argc, const char * argv[]){
int a[120][120];
int n, m;
scanf("%d %d", &n, &m);
// 初始化
for(int i=1; i<=n; i++){
a[i][0] = 0;
a[0][i] = 0;
a[i][1] = 1;
if(i==1){
a[1][i] = 1;
}else{
a[1][i] = 0;
}
}
// 进行计算
for(int i=2; i<=n; i++){
for(int j=2; j<=m; j++){
if(i>=j){
// [1,j,i]
// 分解 [j-1, j] + [j][j] + [j+1][j]
// 1~j-1,可以成为组合的加数,即用1到j-1表示j,=> a[j-1][j]
// j, 可以成为组合的加数,即刚好单个加数{j}表示j, => 1
// j+1~j, 由于这些数都大于j,不可能成为加数 => 0
a[i][j] = a[j-1][j] + 1;
}else{
// [1,i,j]
// 分解 [i-1][j] + [i-1][j-i]
// 加数中无i,从1~i-1中挑选几个数的和等于j => a[i-1][j]
// 加数中有i,从1~i-1中挑选几个数的和加上i等于j,相当于,从1~i-1中挑选几个数的和等于 j-i => a[i-1][j-i]
a[i][j] = a[i-1][j] + a[i-1][j-i];
}
}
}
printf("%d", a[n][m]);
return 0;
}
import java.util.Scanner;
public class Main {
// 整数求和的组合
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt(), m = in.nextInt();
fun(n, m);
}
// 动态规划-01背包-状态压缩
// dp[j] 前i个数字凑出j的可能方案数
// base case:dp[0] = 1
// 方程 dp[i] = dp[i] + dp[j-i]
// 计算顺序 一维逆序计算
public static void fun(int n, int m) {
int[] dp = new int[m+1];
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = m; j >= i; j--) {
dp[j] += dp[j-i];
}
}
System.out.println(dp[m]);
}
}