目录
- 子集和问题
- 最小重量机器设计问题
- 运动员最佳配对问题
- 罗密欧与朱丽叶的迷宫问题
子集和问题
问题描述
解析
注意一下进入左右子树的条件,记录一个剩下的总的和,当前的和加上剩下的和大于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();
}
}
}