回溯法四个习题小练-(子集和问题,最小重量机器设计问题,运动员最佳配对问题,罗密欧与朱丽叶的迷宫问题)

目录

  • 子集和问题
  • 最小重量机器设计问题
  • 运动员最佳配对问题
  • 罗密欧与朱丽叶的迷宫问题

子集和问题

问题描述

这里写图片描述

解析

注意一下进入左右子树的条件,记录一个剩下的总的和,当前的和加上剩下的和大于bestSum的时候才进入右子树,然后用回溯法求解即可。

import java.io.BufferedInputStream;
import java.util.Scanner;

/**
 * 回溯法解决子集和问题
 * @author 郑鑫
 *
 */
public class SubSum {
    private int n;
    private int C; //给出的总和
    private int nowW;
    private int bestW;
    private int Cleft;
    private int[] w; //每一个的权重
    private int[] x;
    private int[] bestX;

    public SubSum(int n, int c, int nowW, int bestW, int cleft, int[] w, int[] x, int[] bestX) {
        super();
        this.n = n;
        C = c;
        this.nowW = nowW;
        this.bestW = bestW;
        Cleft = cleft;
        this.w = w;
        this.x = x;
        this.bestX = bestX;
    }

    public boolean backTrack(int i){
        if(i >= n){
            for(int j = 0; j < i; j++)bestX[j] = x[j];
            bestW = nowW;
            if(C == bestW)return true;
            return false;
        }
        Cleft -= w[i];
        if(nowW + w[i] <= C){  //进入左子树
            x[i] = 1;
            nowW += w[i];
            if(backTrack(i+1))return true;
            x[i] = 0;
            nowW -= w[i];
        }
        if(nowW + Cleft > bestW){
            x[i] = 0;
            if(backTrack(i+1))return true;
        }
        Cleft += w[i];
        return false;
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        int n = cin.nextInt(),C = cin.nextInt();
        int[] w = new int[n+1];
        int[] x = new int[n+1],bestX = new int[n+1];
        int Cleft = 0,nowW = 0,bestW = 0;
        for(int i = 0; i < n; i++){
            w[i] = cin.nextInt();
            Cleft += w[i];
        }

        SubSum ss = new SubSum(n, C, nowW, bestW, Cleft, w, x, bestX);
        ss.backTrack(0);
        //System.out.println(ss.bestW);
        for(int i = 0; i < n; i++)if(bestX[i] == 1)System.out.print(w[i] + " ");
        System.out.println();
    }
}

最小重量机器设计问题

问题描述

这里写图片描述

解析

也是一个经典的回溯法习题

import java.io.BufferedInputStream;
import java.util.Scanner;
/**
 * 最小重量机器设计问题
 * @author 郑鑫
 */
public class Machine {
    private static int n,m,C,nowW = 0,bestW = 0,nowV = 0;
    private static int[][] w;
    private static int[][] v;
    private static int[] x,bestX;

    private static void BackTrack(int i){
        if(i >= n){
            for(int j = 0; j < i; j++)bestX[j] = x[j];
            bestW = nowW;
            return ;
        }
        else for(int j = 0; j < m; j++){
            x[i] = j;
            nowW += w[i][j];
            nowV += v[i][j];
            if(nowV <= C && nowW < bestW)BackTrack(i+1);
            nowW -= w[i][j];
            nowV -= v[i][j];
        }
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        n = cin.nextInt();
        m = cin.nextInt();
        C = cin.nextInt();
        v = new int[n+1][n+1];w = new int[n+1][n+1];
        x = new int[n+1]; bestX = new int[n+1];
        int MAXW = 0;
        for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)v[i][j] = cin.nextInt(); 
        for(int i = 0; i < n; i++)for(int j = 0; j < n; j++){
            w[i][j] = cin.nextInt(); 
            MAXW += w[i][j];
        }
        bestW = MAXW;
        BackTrack(0);
        System.out.println(bestW);
        for(int i = 0; i < n; i++)System.out.print(bestX[i] + 1 + " ");
        System.out.println();
        cin.close();
    }
}

运动员最佳配对问题

问题描述

这里写图片描述

解析

还是用一个数组r[i]表示第i个男运动员配对的女运动员,然后每次交换两个搭档,看能不能使得和更大,更大的话就记录

import java.io.BufferedInputStream;
import java.util.Scanner;

/**
 * 羽毛球运动员配对问题
 * @author 郑鑫
 */
public class BadmintonMatches {
    private static int[][] P,Q;
    private static int[] r,bestR;
    private static int n,bestSum;

    public static void swap(int[] arr,int a,int b){
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp; 
    }

    public static void BackTrack(int i){
        if(i >= n){
            int sum = 0; 
            for(int j = 0; j < n; j++)sum += P[j][r[j]] * Q[r[j]][j];
            if(sum > bestSum){
                bestSum = sum;
                for(int j = 0; j < n; j++)bestR[j] = r[j];
            }
        }else for(int j = i; j < n; j++){
            swap(r, i, j);
            BackTrack(i+1);
            swap(r, i, j);          
        }
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        n = cin.nextInt();
        P = new int[n+1][n+1];  Q = new int[n+1][n+1];
        r = new int[n+1];bestR = new int[n+1];
        for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)P[i][j] = cin.nextInt();
        for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)Q[i][j] = cin.nextInt();

        //r[i]表示第i个男运动员配对的女运动员
        for(int i = 0; i < n; i++)r[i] = i;  //一开始 i -> i
        for(int i = 0; i < n; i++)bestR[i] = i;
        bestSum = 0;
        BackTrack(0);
        System.out.println(bestSum);
        for(int i = 0; i < n; i++)System.out.print(i+1 + "-->" +(bestR[i]+1) + "\n");
        System.out.println();
    }
}

罗密欧与朱丽叶的迷宫问题

问题描述

这里写图片描述

解析

注意一下判断越界的函数,和最少转弯的条数,注意转弯条件的判断di != i ,还有就是dep = 1的时候,第一次不算做转弯,然后也是回溯法求解。

import java.io.BufferedInputStream;
import java.util.Scanner;

public class SearchLuoMiOuYe {
    //控制方向
    private static int[] dx = {0,1,1, 1, 0,-1,-1,-1};
    private static int[] dy = {1,1,0,-1,-1,-1, 0, 1};
    //罗密欧和朱丽叶的位置
    private static int startX,startY,endX,endY;
    private static int n,m,k; //行数,列数,被封闭的房间
    private static int dirs,minn,count;
    private static int[][] board,best;

    public static boolean check(int x,int y){
        return (x > 0 && x <= n && y > 0 && y <= m && board[x][y] == 0);  
    }

    public static void Search(int x,int y,int dep,int di){
        if(dep == n*m - k && x == endX && y == endY && dirs <= minn){
            if(dirs < minn){
                minn = dirs;
                count = 1;
                for(int i = 1; i <= n; i++)
                    for(int j = 1; j <= m; j++)
                        best[i][j] = board[i][j];
            }else count++;
            return ;
        }else for(int i = 0; i < 8; i++){
            int nx = x + dx[i],ny = y + dy[i];
            if(check(nx, ny)){
                if(di != i && dep > 1)dirs++;
                board[nx][ny] = dep+1;
                Search(nx, ny, dep+1, i);
                if(di != i && dep > 1)dirs--;
                board[nx][ny] = 0;
            }
        }
    }

    public static void main(String[] args) {
        Scanner cin = new Scanner(new BufferedInputStream(System.in));
        n = cin.nextInt();
        m = cin.nextInt();
        k = cin.nextInt();
        board = new int[n+1][m+1];
        best = new int[n+1][m+1];
        for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)board[i][j] = 0;
        for(int i = 0; i < k; i++){
            int a = cin.nextInt(); int b = cin.nextInt();
            board[a][b] = -1; //标记封闭的房间 
        }
        startX = cin.nextInt();
        startY = cin.nextInt();
        endX = cin.nextInt();
        endY = cin.nextInt();

        minn = 1000000;
        board[startX][startY] = 1;
        Search(startX, startY, 1, 0);
        System.out.println(minn + "\n" + count);
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++)
                System.out.print(best[i][j] + " ");
            System.out.println();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zxzxzx0119/article/details/80055980