两道关于回溯法,分支限界法的算法题

Posted handsomecui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两道关于回溯法,分支限界法的算法题相关的知识,希望对你有一定的参考价值。

1.最小重量机器设计问题:设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设 wij    是从供应商j处购得的部件 i 的重量, cij 是相应的价格。试设计一个算法,给出总价格不超过 c 的最小重量机器设计。

方法一:回溯法设计:

import static org.junit.Assert.*;

import java.util.Scanner;

import org.junit.Test;

public class 最小重量机器 {
    
    /*
     * 3 3
     * 3 2  1 4  5 6
     * 1 4  3 2  5 6
     * 5 6  3 2  1 4
     * 10
     * 
     * 答案是5
     */
    private static int w[][];
    private static int c[][];
    private static int vis[][];
    private static int n, m, cc;
    private static int ans;
    private static Scanner cin;
    static{
        cin = new Scanner(System.in);
    }
    private static void init() {
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                vis[i][j] = 0;
            }
        }
        ans = Integer.MAX_VALUE;
    }
    public static void main(String[] args) {
        System.out.println("请输入部件数目以及供货商数量n和m:");
        n = cin.nextInt();
        m = cin.nextInt();
        w = new int[n][m];
        c = new int[n][m];
        vis = new int[n][m];
        System.out.println("n行代表n个部件,每行输入每个供货商供应此部件的重量以及价格:");
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                w[i][j] = cin.nextInt();
                c[i][j] = cin.nextInt();
            }
        }
        System.out.println("请输入不超过的价格p:");
        cc = cin.nextInt();
        init();
        work(0, cc, 0, 0);
        if(ans == Integer.MAX_VALUE){
            System.out.println("不能找出总价格不超过 c的最小重量机器的方案");
        }else{
            System.out.println("满足方案的最小重量是:" + ans);
        }
    }
    private static void work(int i, int cc, int ww, int p){
        if(i == n){
            if(p <= cc){
                ans  = Math.min(ans, ww);
            }
            return;
        }
        for(int j = 0; j < m; j++){
            vis[i][j] = 1;
            work(i + 1, cc, ww + w[i][j], p + c[i][j]);
            vis[i][j] = 0;
        }
        
    }
    
}

 分支限界法:

import static org.junit.Assert.*;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

import javax.management.Query;

import org.junit.Test;

class Node{
    private int curw, curv;
    private int units_i;
    private int[] route;
    Node(){
        route = new int[110];
    }
    public Node(int curw, int curv, int units_i, int[] route) {
        super();
        this.curw = curw;
        this.curv = curv;
        this.units_i = units_i;
        this.route = route;
    }
    public int getCurw() {
        return curw;
    }
    public void setCurw(int curw) {
        this.curw = curw;
    }
    public int getCurv() {
        return curv;
    }
    public void setCurv(int curv) {
        this.curv = curv;
    }
    public int getUnits_i() {
        return units_i;
    }
    public void setUnits_i(int units_i) {
        this.units_i = units_i;
    }
    public int[] getRoute() {
        return route;
    }
    public void setRoute(int[] route) {
        this.route = route;
    }
    
}

public class 最小重量设计_分支限界法 {
    
    /*
     * 3 3
     * 3 2  1 4  5 6
     * 1 4  3 2  5 6
     * 5 6  3 2  1 4
     * 10
     * 
     * 答案是5
     */
    private static int w[][];
    private static int c[][];
    private static int n, m, cc;
    private static Scanner cin;
    private static Queue<Node>q;
    static{
        cin = new Scanner(System.in);
        q = new LinkedList<Node>();
    }


    public static void main(String[] args) {
        System.out.println("请输入部件数目以及供货商数量n和m:");
        n = cin.nextInt();
        m = cin.nextInt();
        w = new int[n][m];
        c = new int[n][m];
        
        System.out.println("n行代表n个部件,每行输入每个供货商供应此部件的重量以及价格:");
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                w[i][j] = cin.nextInt();
                c[i][j] = cin.nextInt();
            }
        }
        System.out.println("请输入不超过的价格p:");
        cc = cin.nextInt();
        q.clear();
        int[] route = new int[110];
        Node e = new Node(0, 0, -1, route);
        q.add(e);
        int ans = Integer.MAX_VALUE;
        while(!q.isEmpty()){
            e = q.poll();
            
            for(int j = 0; j < m; j++){
                int i = e.getUnits_i() + 1;
                if(i >= n){
                    
                    if(e.getCurv() <= cc){
                        if(ans > e.getCurw()){
                            ans = Math.min(ans, e.getCurw());
                            route = e.getRoute();
                        }
                    }
                    continue;
                }
                int curv = e.getCurv() + c[i][j];
                int curw = e.getCurw() + w[i][j];
                
                int[] lastroute = e.getRoute();
                int[] curroute = new int[110];
                for(int k = 0; k <= e.getUnits_i(); k++){
                    curroute[k] = lastroute[k];
                }
                curroute[i] = j;
                
                q.add(new Node(curw, curv, i, curroute));
            }
        }
        if(ans == Integer.MAX_VALUE){
            System.out.println("不能找出总价格不超过 c的最小重量机器的方案");
        }else{
            System.out.println("满足方案的最小重量是:" + ans);
            System.out.println("方案是:");
            for(int j = 0; j < n; j++){
                System.out.print(route[j] + " ");
            }
            
        }
    }
    
    
}


2.最大 k 乘积问题: 设    I 是一个 n 位十进制整数。如果将 I 划分为 k 段,则可得到    k 个整数。这 k 个整数的乘积称为 I 的一个 k 乘积。试设计一个算法,对于给定的 I 和 k ,求出 I 的最大 k 乘积。

回溯法设计:

 

import java.util.Scanner;


public class 最大k成绩 {
    private static long ans;
    private static Scanner cin;
    static{
        cin = new Scanner(System.in);
    }
    static void work(int cur, int i, int k, long v){
        //System.out.println("i = " + i + " cur = " + cur + " k = " + k);
        if(i == k){
            ans = Math.max(ans, v);
            return;
        }
        if(cur == 0){
            return;
        }
        int MOD = 1;
        while(cur / MOD != 0){
            work(cur % MOD, i + 1, k, v * (cur / MOD));
            MOD *= 10;
        }
    }
    public static void main(String[] args) {
        int num, k;
        System.out.println("请输入数字num和要分成的段数k: ");
        while(cin.hasNext()){
            num = cin.nextInt();
            k = cin.nextInt();
            ans = Long.MIN_VALUE;
            work(num, 0, k, 1L);
            if(ans == Long.MIN_VALUE){
                System.out.println("整数" + num + "不能被分成" + k + "段");
            }else{
                System.out.println(num + "的最大" + k + "乘积是: " + ans);
            }
            System.out.println("请输入数字num和要分成的段数k: ");
        }
    }
}

 

以上是关于两道关于回溯法,分支限界法的算法题的主要内容,如果未能解决你的问题,请参考以下文章

五大常用算法:分支限界法

回溯法与分支限界

回溯法与分支限界

分支界限

回溯法与分支限界

回溯法与分支限界