提示:养成看目录的好习惯哦!!
前言
回溯法 – 深度优先搜素
简单概述
回溯法思路的简单描述是:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。
实验八:使用回溯算法解决多个数和的问题(Sum It Up)(完成实验报告三、四、五、六的内容)
一、实验目的
练习使用回溯算法解决实际问题(使用Java语言实现)。
二、实验内容
给出一个n,k,再给出n个数中,输出所有的可能使几个数的和等于k的组合,输入的n和k的值都为0时退出。【示例】
输入样例:
6 | |||||
---|---|---|---|---|---|
4 | 3 | 2 | 2 | 2 | 2 |
4 | |||||
3 | |||||
2 | 1 | 1 | |||
5 | |||||
12 | |||||
50 | 50 | 50 | 50 | 50 | 50 |
25 | 25 | 25 | 25 | 25 | 25 |
400 |
输出样例:
4 | |||
---|---|---|---|
4 | 3+1 | 2+2 | 2+1+1 |
5 | |||
没有 | |||
400 | |||
50+50+50+50+50+50+25+25+25+25 | 50+50+50+50+50+25+25+25+25+25+25 |
二、设计思路
回溯算法思路虽简单,但是具体实现解空间树,较为复杂,本次实验,首先先写好一个回溯方法,然后利用循环和嵌套递归,逐步实现数组中的数在满足条件时是需要 加 还是 跳过 ,思路较为粗糙也不够完善,但可运行基本满足实验需要!内容仅供参考!!!
1.定义变量
定义变量:
private int n;//数的个数
private int k;//要凑成的数
private int[] a;;//所有子数
private int bestValue=0;//当前最优价值
private int cn=0;//当前数的总和
private boolean[] picking;//picking[i]表示第 i个数是否可以相加
Scanner scan =new Scanner(System.in);
2.构造方法
菜单函数:
public void menu(){
do {
get();
}while (n!=0||k!=0);
}
获取数据:
public void get(){
k = scan.nextInt();
n = scan.nextInt();
picking = new boolean[n + 1];
a = new int[n+2];
for (int i=1;i<=n;i++){
a[i]=scan.nextInt();//数字大小
}
output3();
for (int i=1;i<=n;i++){
cn=0;
for (int x=1;x<=n;x++){
picking[x]=false;
}
backtrack(i);
}
output2(picking);
}
构建解空间树:
void backtrack(int t){ //用于搜索空间数,t 表示当前扩展结点在第 t 层
if(t>n){//已经到达叶子结点
return ;
}
if(cn+a[t]<k){ //如果满足和小于k值时,则搜索左子树
picking[t]=true;
cn+=a[t];
backtrack(t+1);
if(cn+a[t+1]<k){
cn-=a[t];
picking[t]=false;
backtrack(t+1);
}else return;
}
if(cn+a[t]>k){ //如果满足和大于k值时,则搜索右子树
picking[t]=false;
backtrack(t+1);
if(cn+a[t-1]<k){
cn-=a[t-1];
picking[t-1]=false;
backtrack(t+2);
}
}
if(cn+a[t]==k){//当恰好和为k值时
picking[t]=true;
output1(picking);
}
}
输出情况1:
public void output1(boolean[] picking){//输出符合条件的组合
int lastTrueLocation=0;
for (int i=1;i<=n;i++){
if (picking[i]==true) {
lastTrueLocation=i;
}
}
for (int j=1;j<=n;j++){
if (picking[j]==true){
if(j!=lastTrueLocation)
{
System.out.print(a[j]+"+");
}else {
System.out.print(a[j]);
}
}
}
System.out.println();
}
输出情况2:
public void output2(boolean[] picking){//输出符合条件的组合
int lastTrueLocation=0;
for (int i=1;i<=n;i++){
if (picking[i]==false) {
lastTrueLocation=i;
}
}
for (int j=1;j<=n;j++){
int aa=0;
if (picking[j]==false){
if(j==lastTrueLocation){
aa++;
}
}
if(aa+1==a.length)
System.out.println("没有符合要求的");
}
}
输出情况3:
public void output3(){
int aaa=0;
for (int j=1;j<=n;j++){
aaa+=a[j];
}
if (aaa<k){
System.out.println("没有符合要求的");
}
}
3.运行
运行程序:
public class Do {
public static void main(String[] args) {
SumUP sumUP =new SumUP();
sumUP.menu();
}
}
4.结果
测试结果:
总结
以上就是今天要分享的全部内容,本文仅仅简单展示了对该实验的解题想法,回溯法是目前所有实验中,我耗时最久的一次实验,考虑了很久,可惜能力有限,仍未实现算法的普遍性。希望能有志同道合之人交流沟通,以得到解决。
欢迎扫取以下二维码,前来我的公众号玩耍