算法作业04(回溯与分支界限算法)(骑士游历与行列变换问题)

1.骑士游历问题

问题描述

在国际象棋的棋盘(8行×8列)上放置一个马,按照“马走日字”的规则,马要遍历棋盘,即到达棋盘上的每一格,并且每格只到达一次。若给定起始位置(x0,y0),编程探索出一条路径,沿着这条路径马能遍历棋盘上的所有单元格。

问题分析

设当前马在棋盘的某个位置(x, y)上,按照规则,下一步有8个方向可走。设二维数组mat表示棋盘,每个元素表示棋盘的一格,其值定义如下:0表示马未到达过,Mat[i, j]= -1表示棋盘边界,自然数表示马到达该格的步数。

            

设计思想

马从棋盘上的某一初始位置(x0,y0)开始,每次选择一个方向k,向前走一格,直到走完64格为止。每走一格,设置数组中相应格的元素值为马走的步数。 如果选择的方向k=0,表示可能的8种走向都试探不通,不通的原因是走向超出了棋盘范围,或当前位置已经被马访问过。此时马已无路可走,说明前几步走得不对,应该退回去重新换一种走法,这种逐步试探的设计思想称为回溯算法。 回溯算法在每一格上朝一个方向盲目地进行试探,遇到在某一格上所有方向都不能走通时,才回到前一格上来试探另一个方向。当每一格上的所有方向都试探过,不能走通时,才做出“走不通”的结论。因此该算法在探索时带有一定的盲目性和随机性,运行效率较低。

接下来上代码:

import java.util.*;
public class QS {  

 private boolean Travel(int firstX, int firstY, int[][] board) {  

		int[] movex = { -2, -1, 1, 2,  2,  1, -1, -2 };  
		int[] movey = {  1,  2, 2, 1, -1, -2, -2, -1 };  

		int[] nextStepX = new int[board.length];  
		int[] nextStepY = new int[board.length];  
        
		int[] exitS = new int[board.length];  
		int nextX = firstX;  
		int nextY = firstY;  
		board[nextX][nextY] = 1; 
		
		for (int m = 2; m <= Math.pow(board.length, 2); m++) {  

			for (int i = 0; i <board.length; i++) {  
				exitS[i] = 0;   
                }  

			int count = 0;              
			for (int i = 0; i < 8; i++) {  
				int temI = nextX + movex[i];  
				int temJ = nextY + movey[i];  				
                
				if (temI< 0 || temI> 7 || temJ< 0 || temJ> 7) {  
					continue;  
                    }  
				
				if (0 == board[temI][temJ]) {  
					nextStepX[count] = temI; 
					nextStepY[count] = temJ;  
					count++;   
                    }  
                }  

			int min = -1;  
			if (count == 0) {  
				return false;  
			}  

			if (1 == count) {  
				min = 0;  
				} 
			else {
					for (int i = 0; i < count; i++) {  
						for (int j = 0; j < 8; j++) {  
							int temI = nextStepX[i] + movex[j];  
							int temJ = nextStepY[i] + movey[j];  
							if (temI< 0 || temI> 7 || temJ< 0 || temJ> 7) {  
								continue;  
                            }  

							if (0 == board[temI][temJ]) {  
								exitS[i]++;  
                            }  
                        }  
                    }  
					
					int tem = exitS[0];  
					min = 0;  

					for (int i = 1; i < count; i++) {  
						if (tem >exitS[i]) {  
							tem = exitS[i];  
							min = i;  
                        }  
                    }  
                }  

			nextX = nextStepX[min];  
			nextY = nextStepY[min];  
			board[nextX][nextY] = m;  
            }  

		return true;  
        }  

public static void main(String[] args) {  

	int firstX, firstY;  
	System.out.println("输入起始点(0-7):");  
    Scanner scanner = new Scanner(System.in);  

    firstX = scanner.nextInt();  
    firstY = scanner.nextInt();  
    int[][] board = new int[8][8];  
    QS knight = new QS();  

    if (knight.Travel(firstX, firstY, board)) {  
    	System.out.println("游历完成:");  
            } else {  
            	System.out.println("游历失败!\n");  
            }  

    for (int i = 0; i <board.length; i++) {  
    	for (int j = 0; j < board[0].length; j++) {  
    		if (board[i][j] < 10) {  
    			System.out.print(" " + board[i][j]);  
                    } else {  
                    	System.out.print(board[i][j]);  
                    }  
    		System.out.print(" ");  
                }  
    	System.out.println();  
            }  
        }  
    }  

运行结果

 

2.行列变换问题

问题描述

给定两个mn方格阵列组成的图形A和图形B,每个方格的颜色为黑色或白色,如下图所示。行列变换问题的每一步变换可以交换任意2行或2列方格的颜色,或者将某行或某列颠倒。上述每次变换算作一步。试设计一个算法,计算最少需要多少步,才能将图形A变换为图形B。

问题分析

先进先出队列式分支限界法

在当前节点(扩展节点)处,先生成其所有的儿子节点(分支),然后再从当前的活节点(当前节点的子节点)表中选择下一个扩展节点。为了有效地选择下一个扩展节点,加速搜索的进程,在每一个活节点处,计算一个函数值(限界),并根据函数值,从当前活节点表中选择一个最有利的节点作为扩展节点,使搜索朝着解空间上有最优解的分支推进,以便尽快地找出一个最优解。分支限界法解决了大量离散最优化的问题。

队列式分支限界法将活节点表组织成一个队列,并将队列的先进先出原则选取下一个节点为当前扩展节点。

算法步骤:

输入数据,将计算出的最少变换次数和相应的变换序列输出。第1 行是最少变换次数。从第2 行开始,每行用4 个数表示一次变换。

接下来上代码

import java.util.LinkedList;
import java.util.Scanner;
class graph{
	static int sour, dest;
	static int ans[]=new int[1<<16];
	int m=4,n=4,x;
	int row[]=new int[4];
	int col[]=new int[4];
	void setx(int x){
		this.x=x;
	}
	int getx(){
		return this.x;
	}
	
	void rowx(){
		int y;		
		for(int i=0;i<m;i++){
			y=1;
			row[i]=0;
			for(int j=0;j<n;j++){
				if((x&1)!=0) 
					row[i]|=y;
				y<<=1;
				x>>=1;
			}
		}
	}
	
	void colx(){
		int y;		
		for(int j=0;j<n;j++) col[j]=0;
		y=1;
		for(int i=0;i<m;i++){
			for(int j=0;j<n;j++){
				if((x&1)!=0) 
					col[j]|=y;
				x>>=1;
			}
			y<<=1;
		}
	}
	
	void rowy(){
		int  z=1, x=0, y;
		for(int i=0;i<m;i++){
			y=row[i];
			for(int j=0;j<n;j++){
				if((y&1)!=0) 
					x|=z;
				z<<=1;
				y>>=1;
			}
		}
		this.x=x;
	}
	
	void coly(){
		int  z=1, x=0, y;
		for(int i=0;i<m;i++){
			for(int j=0;j<n;j++){
				if((col[j]&1)!=0) 
					x|=z;
				z<<=1;
				col[j]>>=1;
			}
		}
		this.x=x;
	}
	
	void Swaprow(int i, int j){
		int o;
		o=row[i];
		row[i]=row[j];
		row[j]=o;
	}
	
	void Swapcol(int i, int j){
		int o;
		o=col[i];
		col[i]=col[j];
		col[j]=o;
	}
	
	void reveR(int k){
		int y=0, z=1<<(4-1);
		for(int j=0;j<4;j++){
				if((row[k]&1)!=0) 
					y|=z;
				z>>=1;
		row[k]>>=1;
			}
		row[k]=y;
	}
	
	void reveC(int k){
		int y=0, z=1<<(4-1);
		for(int j=0;j<4;j++){
				if((col[k]&1)!=0) 
					y|=z;
				z>>=1;
		col[k]>>=1;
			}
		col[k]=y;
	}
	
	int rowswap(int x, int i, int j){
		this.x=x;
		rowx();
		Swaprow(i,j);
		rowy();
		return this.x;
	}
	
	int colswap(int x, int i, int j){
		this.x=x;
		colx();
		Swapcol(i,j);
		coly();
		return this.x;
	}
	
	int revrow(int x, int k){
		this.x=x;
		rowx();
		reveR(k);
		rowy();
		return this.x;
	}
	
	int revcol(int x, int k){
		this.x=x;
		colx();
		reveC(k);
		coly();
		return this.x;
	}
	
}
public class HL {

	public static void main(String[] args){	
		final int Maxsize=1<<16;
		graph  gN;
		int E=0;
		int N=0;
		gN=new graph();
		int hash[]=new int[1<<16];
		int i,j,h=0;char c;
		graph G1=new graph();
		
		Scanner scanner = new Scanner(System.in);  
		String ss=scanner.nextLine();
		char[]chArrs=ss.toCharArray();
		for(graph.sour=i=0;i<16;i++){
			c=chArrs[i];
			graph.sour|=(int)(c-'0')<<i;
		}
		String sd=scanner.nextLine();
		char[]chArrd=sd.toCharArray();
		for(graph.dest=i=0;i<16;i++){
			c=chArrd[i];
			graph.dest|=(int)(c-'0')<<i;
		}

		LinkedList  queue=new LinkedList();
		for(int k=0; k<Maxsize;k++)hash[k]=-1;
		G1.x=graph.sour;
		hash[G1.x]=0;
		queue.add(G1.x);
		while(!queue.isEmpty()){
			E=(int)queue.removeFirst();

			for(i=0;i<4-1;i++){
				for(j=i+1;j<4;j++){
					gN.x=gN.rowswap(E,i,j);
					N=gN.x;
					if(hash[N]==-1){
						hash[N]=hash[E]+1;
						graph.ans[N]=E;
						queue.add(N);						
					}
				}
			}	
			for(i=0;i<4-1;i++){
				for(j=i+1;j<4;j++){
					gN.x=gN.colswap(E,i,j);
					N=gN.x;
					if(hash[N]==-1){
						hash[N]=hash[E]+1;
						graph.ans[N]=E;
						queue.add(N);
					}
				}
			}
			for(i=0;i<4;i++){
					gN.x=gN.revrow(E,i);
					N=gN.x;
					if(hash[N]==-1){
						hash[N]=hash[E]+1;
						graph.ans[N]=E;
						queue.add(N);
					}
			}
			for(i=0;i<4;i++){
				gN.x=gN.revcol(E,i);
				N=gN.x;
				if(hash[N]==-1){
					hash[N]=hash[E]+1;
					graph.ans[N]=E;
					queue.add(N);
				}				
			}

			if(hash[graph.dest]!=-1){
				System.out.println("OK");break;
		}
			
			
		}
		System.out.println(hash[graph.dest]);
		output(graph.dest);
		
	
	}
	public static void outb(int x){
		for(int i=0; i<4;i++){
			for(int j=0;j<4;j++){
				if((x&1)!=0)System.out.print(1);
				else System.out.print(0);
				x/=2;
			}
			System.out.println();			
		}
	}
	public static void output(int N){
		if(N==graph.sour){
			System.out.println();
			outb(N);
			return;
		}
		output(graph.ans[N]);
		System.out.println();
		outb(N);
	}
}

运行结果:

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Y?Ire: TO

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

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

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

打赏作者

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

抵扣说明:

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

余额充值