题目描述如下:
描述
给定整数a1、a2、…….an,判断是否可以从中选出若干数,使它们的和恰好为K。
输入
首先,n和k,n表示数的个数,k表示数的和。
接着一行n个数。
(1<=n<=20,保证不超int范围)
输出
如果和恰好可以为k,输出“YES”,并按输入顺序依次输出是由哪几个数的和组成,否则“NO”
样例输入
4 13
1 2 4 7
样例输出
YES
2 4 7
take notes:
解法一:按照全排列的思想,将dfs写在for循环里面,先选1 2 4 7,发现超过k要求的数之后回溯,用一个book数组做标记,如果没有用过的可以用,用过的数只能向下走找到一个没用过的数,进行运算。这样写只能求一种情况,若答案有多种,要用解法二。
import java.util.Scanner;
public class Main {
static int n,k;
static boolean flag = false;
static int[] ans = new int[20];
static int[] book = new int[20];
static void dfs(int x,int sum){
if(sum==k){
flag=true;
return;
}
if(sum>k){
return;
}
else{
for(int i=0;i<n;i++){
if(book[i]==0){
book[i]=1;
dfs(x+1,sum+ans[i]);
if(flag==true)return;
book[i]=0;
}
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
n=in.nextInt();
k=in.nextInt();
for(int i=0;i<n;i++){
ans[i] = in.nextInt();
}
dfs(0,0);
if(flag==true){
System.out.println("YES");
for(int i=0;i<n;i++){
if(book[i]==1){
System.out.print(ans[i]+" ");
}
}
}
else System.out.println("NO");
}
}
解法二:可以解出多种答案,不需要for循环和book数组,而是需要一个新的数组来存放满足条件的答案,中心思想就是,当前这个数要还是不要,如果要则应该加在sum中,若不要则减掉,但是无论要还是不要x都要加一,也就是都要往后走,通过存放结果的数组的下表m–来实现回溯,这里重点要注意,dfs里面的参数不要动!
import java.util.Scanner;
public class Main {
static int n,k,m;
static int[] ans = new int[20];
static int[] bns = new int[20];
static boolean flag = false;
static void dfs(int x,int sum){
if(sum==k){
System.out.println("YES");
for(int i=0;i<m;i++){
System.out.print(bns[i]+" ");
}
System.out.println();
flag=true;
return;
}
if(sum>k ||x==n){
return;
}
else{
sum=sum+ans[x];
bns[m]=ans[x];
m++;
dfs(x+1,sum);
m--;
sum=sum-ans[x];
dfs(x+1,sum);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
n=in.nextInt();
k=in.nextInt();
for(int i=0;i<n;i++){
ans[i]=in.nextInt();
}
m=0;
dfs(0,0);
if(flag==false)System.out.println("NO");
}
}
分享一组样例
输入
4 13
3 10 4 6
输出
YES
3 10
YES
3 4 6