兩道關於回溯法,分支限界法的算法題


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: ");
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM