回溯算法——装载问题和8皇后问题

装载问题

代码(附解题思路)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Load {
    public static Scanner scanner = new Scanner(System.in);
    public static int weight1;  //第一个集装箱的载重能力
    public static int weight2; //第二个集装箱的载重能力
    public static int n;  // n个集装箱
    public static int maxWeight=0; //做大载重量
    public static int sum1 = 0, sumAll = 0;  //sum1表示第一个集装箱的重量,sumAll表示所有集装箱的重量
    public static int[] items;  //记录集装箱的重量
    public static int []record;
    public static int []bestRecord;

    public static void main(String args[]) {
        n = scanner.nextInt();
        items = new int[n];
        bestRecord=new int[n];
        record=new int[n];
        weight1 = scanner.nextInt();
        weight2 = scanner.nextInt();
        for (int i = 0; i < n; i++) {
            items[i] = scanner.nextInt();
        }
        backtrack(0);
        System.out.println(maxWeight);
//        System.out.println(record);
        for (int i = 0; i < n; i++) {
            System.out.print(bestRecord[i] + " ");
        }
    }

    //回溯求解
    public static void backtrack(int i) {
        //集装箱超载
        if(sum1>weight1){
            return;
        }
        // 当前已经到达叶子节点
        if(i==n){
//            System.out.println(record);
//            record.remove(record.size()-1);
            if(sumAll-sum1<=weight2){ //能全部装下
                if(sum1>maxWeight){
                    for (int j = 0; j < n; j++) {
                        bestRecord[j]=record[j];
                    }
                    maxWeight=sum1;
                }
            }
            return;
        }
        //左子树遍历,装当前货物到第一个集装箱
        sum1+=items[i];
        record[i]=1;
        backtrack(i+1);
        //右子树遍历,当前货物不装到第一个集装箱
        sum1-=items[i];
        record[i]=0;
        backtrack(i+1);


    }
}

运行结果

输入
5
10 10
20 3 5 6 8
输出
9
0 1 0 1 0
image.png

8皇后问题

代码(附思路)

import java.util.Scanner;

public class Queue {
    static int num;
    static Scanner scanner = new Scanner(System.in);

    public static void main(String args[]) {
        int[] x = new int[8]; //下标代表第几行,值代表放在该行的哪一个位置
        int n = 8;
        for (int i = 0; i < n; i++) {
            x[i] = -1;  //初始化每个位置都没放皇后
        }
        Bhh(0, 8, x);
        System.out.println("共有:" + num + "种组合");
    }

    private static void Bhh(int k, int n, int[] x) {
        for (int i = 0; i < n; i++) {
            if (Wzhi(k, i, x)) {
                x[k] = i;
                if (k == n - 1) {
                    for (int j = 0; j < n; j++) {
                        {
                            System.out.print(x[j] + " ");
                        }
                    }
                    num++;
                    System.out.println();
                } else {
                    Bhh(k + 1, n, x);
                }

            }
        }
    }


    private static boolean Wzhi(int k, int i, int[] x) {
        for (int j = 0; j < k; j++) {
            //判断是否同一列,判断是否在对角线上(利用两直角边长度相同)
            if ((i == x[j]) || (Math.abs((k - j)) == Math.abs(i - x[j]))) {
                return false;
            }
        }
        return true;
    }

}

运行结果

输出
0 4 7 5 2 6 1 3
0 5 7 2 6 3 1 4
0 6 3 5 7 1 4 2
0 6 4 7 1 3 5 2
1 3 5 7 2 0 6 4
1 4 6 0 2 7 5 3
1 4 6 3 0 7 5 2
1 5 0 6 3 7 2 4
1 5 7 2 0 3 6 4
1 6 2 5 7 4 0 3
1 6 4 7 0 3 5 2
1 7 5 0 2 4 6 3
2 0 6 4 7 1 3 5
2 4 1 7 0 6 3 5
2 4 1 7 5 3 6 0
2 4 6 0 3 1 7 5
2 4 7 3 0 6 1 5
2 5 1 4 7 0 6 3
2 5 1 6 0 3 7 4
2 5 1 6 4 0 7 3
2 5 3 0 7 4 6 1
2 5 3 1 7 4 6 0
2 5 7 0 3 6 4 1
2 5 7 0 4 6 1 3
2 5 7 1 3 0 6 4
2 6 1 7 4 0 3 5
2 6 1 7 5 3 0 4
2 7 3 6 0 5 1 4
3 0 4 7 1 6 2 5
3 0 4 7 5 2 6 1
3 1 4 7 5 0 2 6
3 1 6 2 5 7 0 4
3 1 6 2 5 7 4 0
3 1 6 4 0 7 5 2
3 1 7 4 6 0 2 5
3 1 7 5 0 2 4 6
3 5 0 4 1 7 2 6
3 5 7 1 6 0 2 4
3 5 7 2 0 6 4 1
3 6 0 7 4 1 5 2
3 6 2 7 1 4 0 5
3 6 4 1 5 0 2 7
3 6 4 2 0 5 7 1
3 7 0 2 5 1 6 4
3 7 0 4 6 1 5 2
3 7 4 2 0 6 1 5
4 0 3 5 7 1 6 2
4 0 7 3 1 6 2 5
4 0 7 5 2 6 1 3
4 1 3 5 7 2 0 6
4 1 3 6 2 7 5 0
4 1 5 0 6 3 7 2
4 1 7 0 3 6 2 5
4 2 0 5 7 1 3 6
4 2 0 6 1 7 5 3
4 2 7 3 6 0 5 1
4 6 0 2 7 5 3 1
4 6 0 3 1 7 5 2
4 6 1 3 7 0 2 5
4 6 1 5 2 0 3 7
4 6 1 5 2 0 7 3
4 6 3 0 2 7 5 1
4 7 3 0 2 5 1 6
4 7 3 0 6 1 5 2
5 0 4 1 7 2 6 3
5 1 6 0 2 4 7 3
5 1 6 0 3 7 4 2
5 2 0 6 4 7 1 3
5 2 0 7 3 1 6 4
5 2 0 7 4 1 3 6
5 2 4 6 0 3 1 7
5 2 4 7 0 3 1 6
5 2 6 1 3 7 0 4
5 2 6 1 7 4 0 3
5 2 6 3 0 7 1 4
5 3 0 4 7 1 6 2
5 3 1 7 4 6 0 2
5 3 6 0 2 4 1 7
5 3 6 0 7 1 4 2
5 7 1 3 0 6 4 2
6 0 2 7 5 3 1 4
6 1 3 0 7 4 2 5
6 1 5 2 0 3 7 4
6 2 0 5 7 4 1 3
6 2 7 1 4 0 5 3
6 3 1 4 7 0 2 5
6 3 1 7 5 0 2 4
6 4 2 0 5 7 1 3
7 1 3 0 6 4 2 5
7 1 4 2 0 6 3 5
7 2 0 5 1 4 6 3
7 3 0 2 5 1 6 4
共有:92种组合
image.png

实验总结

回溯法:把问题的解空间转化成了图或者树的结构表示,然后使用深度优先搜索策略进行遍历,遍历的过程中记录和寻找所有可行解或者最优解。

回溯法按深度优先策略搜索问题的解空间树。首先从根节点出发搜索解空间树,当算法搜索至解空间树的某一节点时,先利用剪枝函数判断该节点是否可行(即能得到问题的解)。如果不可行,则跳过对该节点为根的子树的搜索,逐层向其祖先节点回溯;否则,进入该子树,继续按深度优先策略搜索。

回溯法的基本行为是搜索,搜索过程使用剪枝函数来为了避免无效的搜索。剪枝函数包括两类:1. 使用约束函数,剪去不满足约束条件的路径;2.使用限界函数,剪去不能得到最优解的路径。

问题的关键在于如何定义问题的解空间,转化成树(即解空间树)。解空间树分为两种:子集树和排列树。两种在算法结构和思路上大体相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦码城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值