dp么,轻松化解~
278. 数字组合
给定 N 个正整数 A1,A2,…,AN从中选出若干个数,使它们的和为 M,求有多少种选择方案。
输入格式
第一行包含两个整数 N 和 M。
第二行包含 N 个整数,表示 A1,A2,…,AN
输出格式
包含一个整数,表示可选方案数。
数据范围
1≤N≤100
1≤M≤10000
1≤Ai≤1000
答案保证在 int 范围内。
输入样例:
4 4
1 1 2 2
输出样例:
3
现将题目转化一下,我们可以把要求的和看为容量为m的背包,每一个数字看做货物的重量,那么问题就转化为求刚好装满m个背包的可能情况。成功转化成01背包问题。
注意 这里和背包问题不同的是,这个题要求恰好装满,而且求的是所有可能的情况。这里我们要想一想怎么表示出这两个条件。
法一,记忆化递归
递归函数需要的参数是index (当前正在处理数字的下标)rest (距离目标和还剩下的差)
递归的终止条件就是搜索到最后一个数 的时候,如果这个时候 已经选择的数字之和恰好为m,说明找到了一种情况,返回1,否则返回0;
函数主体处理,我拿到一个数字,我可以选(容量足够前提下),也可以不选,我的总方案数就是二者之和。
这样函数就写完了
但可以想见有大量重复计算,所以我们建立一个数组存一下每次算出的答案,做一个记忆性优化
完整代码如下
package 背包;
import java.math.MathContext;
import java.util.Arrays;
import java.util.Scanner;
public class _278_数字组合 {
static int [][]dp;
static int []a=new int [105];
static int n;
static int m;
//static final int N=1010;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
dp=new int [n+1][m+1];
for(int i=0;i<dp.length;i++)
{
Arrays.fill(dp[i],-1);
}
for(int i=0;i<n;i++)
{
a[i]=sc.nextInt();
}
int c=dfs(0,m);
System.out.println(c);}
static int dfs(int index,int rest)
{
if(dp[index][rest]!=-1) return dp[index][rest];
if(index==n) return rest==0? 1:0;
int ans=0;
ans+=dfs(index+1,rest);//不选
if(a[index]<=rest)//能选则选
//如果是完全背包的话呢?
ans+=dfs(index+1,rest-a[index]);
dp[index][rest]=ans;
return ans;
//dp[index][rest]=Math.max(ans1, ans2);
// return Math.max(ans1, ans2);
}
}
下面是dp版本 注意初始化
package 背包;
import java.math.MathContext;
import java.util.Arrays;
import java.util.Scanner;
public class 数字组合dp优化版本 {
//ac拿下
static int [][]dp;
static int []a=new int [105];
static int n;
static int m;
//static final int N=1010;
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
m=sc.nextInt();
dp=new int [n+1][m+1];
int N=dp.length;
int M=dp[0].length;
for(int i=0;i<n;i++)
{
a[i]=sc.nextInt();
}
dp[N-1][0]=1;//初始化,此时必有一种方法
for(int index=N-2;index>=0;index--)
{
for(int rest=0;rest<M;rest++)
{
int ans=0;
ans+=dp[index+1][rest];//不选
if(a[index]<=rest)//能选则选
//如果是完全背包的话呢?
ans+=dp[index+1][rest-a[index]];
dp[index][rest]=ans;
}
}
System.out.println(dp[0][m]);}
}
新人博主坚持更新不易,可否给博主小小的赞呢?欢迎关注,现在关注绝对不亏