1. 程式人生 > >演算法——回朔法簡介

演算法——回朔法簡介

回溯法簡介及示例

        回溯法是遞迴演算法的一種特殊形式,回溯法的基本思想是:對一個包括很多結點,每個結點有若干個搜尋分支的問題,把原問題分解為對若干個子問題求解的演算法。當搜尋到某個結點、發現無法再繼續搜尋下去時,就讓搜尋過程回溯(即退回)到該節點的前一個結點,繼續搜尋這個節點的其他尚未搜尋的分支;如果發現這個節點也無法再繼續搜尋下去時,就讓搜尋過程回溯到這個結點的前一個結點繼續這樣的搜尋過程;這樣的搜尋過程一直進行到搜尋到問題的解或搜尋完全部可搜尋分支沒有解存在為止。回溯法和簡單的遞迴演算法不同的是:對於回溯演算法, 當對一個結點的子分支搜尋失敗時,要考慮回溯(即退回)至該結點,繼續對該結點的其他尚未搜素過的分支進行搜尋;而簡單的遞迴演算法不需要考慮這些問題。

示例:設計求解迷宮問題的函式及測試。        一個迷宮是一些互相連通的交叉路口的集合,給定一個迷宮入口,一個迷宮出口,當從入口到出口存在通路時輸出其中的一條通路,當從入口到出口不存在通路時輸出無通路存在。每個交叉路口除進來的路之外有三個路口,分別是向左、向前和向右。為簡化設計,假設迷宮中不存在環路。下圖為迷宮的示意圖。
問題分析:每個路口最多有三個搜尋分支。把演算法設計為如下的搜尋過程:把整個搜尋分解為向左、向前和向右三個方向上子問題的搜尋。當搜尋到某個路口,發現該路口沒有可搜尋的方向時,就讓搜尋過程回溯到該路口的前一個路口,然後搜尋這個路口的其他尚未搜尋過的搜尋方向。這樣的搜尋過程一直繼續到找到出口或搜尋完全部可連通路口的所有可能搜尋方向沒有找到出口為止。
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.StringTokenizer;

class InterSection{  //路口類
	int left;  //向左方向
	int forward;  //向前方向
	int right;  //向右方向
}

public class Maze {
	int mazeSize;  //路口個數
	InterSection[] intSec;  //路口集合
	int exit;  //出口
	
	Maze(String fileName) {
		String line;

		try{
			BufferedReader in = new BufferedReader(new FileReader(fileName));
			line = in.readLine();  //讀檔案的第1行
			mazeSize = Integer.parseInt(line.trim());  //去空格並轉換型別
			intSec = new InterSection[mazeSize + 1];
			
			for ( int i = 1 ; i <= mazeSize ; i ++ ) {  //讀檔案的後續行
				line = in.readLine();
				StringTokenizer tokenizer = new StringTokenizer(line);  //把當前行數值轉換成StringTokenizer物件
				InterSection curr = new InterSection();
				curr.left = Integer.parseInt(tokenizer.nextToken());
				curr.forward = Integer.parseInt(tokenizer.nextToken());
				curr.right = Integer.parseInt(tokenizer.nextToken());
				intSec[i] = curr;
			}
			exit = Integer.parseInt(in.readLine());
			in.close();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public boolean travMaze(int intSecValue) {  //搜尋
	//用回朔法搜尋迷宮的所有分支,intSexValue為當前所處路口號
	//當搜尋到出口時函式返回1,否則返回0
		if (intSecValue > 0) {
			if (intSecValue == exit) {  //搜尋成功出口
				System.out.print(intSecValue + "<==");
				return true;
			}
			
			else if (travMaze(intSec[intSecValue].left)) {  //向當前路口的左分支探索
				System.out.print(intSecValue + "<==");
				return true;
			}
			
			else if (travMaze(intSec[intSecValue].forward)) {  //向當前路口的前分支探索
				System.out.print(intSecValue + "<==");
				return true;
			}
			
			else if (travMaze(intSec[intSecValue].right)) {  //向當前路口的右分支探索
				System.out.print(intSecValue + "<==");
				return true;
			}
		}
		
		return false;  //搜尋失敗出口
		
	}
	
	public static void main(String[] args) {
		String fileName = "F:\\Maze.txt";
		Maze m = new Maze(fileName);
		int start = 1;
		
		if (m.travMaze(start)) {
			System.out.println();
			System.out.println("此迷宮的一條通路如上所示");
		}
		else {
			System.out.println("此迷宮無通路出來!");
		}
	}
	
}
資料檔案:(F:\Maze.txt)說明:檔案的第一行是迷宮的路口個數,此檔案表示共有6個路口;第二行到第七行是編號1到編號6的6個路口的狀態,如第2行的0 2 0表示編號1的路口狀態是向左不通,向前通到2號路口,向右不通;最後一行表示迷宮的出口為路口7。 注意:每個路口的向左、向前和向右的方向是站在當前路口的位置來說的,而不是站在路口1的位置來說的。
6
0 2 0
3 5 6
0 0 4
0 0 0 
0 0 0
7 0 0 
7
輸出結果為:
7<==6<==2<==1<==
此迷宮的一條通路如上所示