Backtracking: The core idea of backtracking algorithms learn from the movie The Butterfly Effect

Backtracking: From the film "The Butterfly Effect> learn core idea of ​​backtracking algorithm

Sudoku, eight queens, 0-1 backpacks, colored drawing, traveling salesman problem, problems can use the full array

Understanding "backtracking"

Thinking back, similar to the search enumeration, enumeration of all solutions, find solutions to meet the expectations, in order to regularly enumerate all possible solutions to the problem solving process is divided into several stages, each stage, will face a fork in the road, just pick the first one way, find the time when the road does not make sense (does not meet expectations) to fall back on a fork in the road, select another.

Eight queens problem:

There is a 8x8 board, fill it up 8 pieces (Queen), where each piece rows, columns, diagonals can not have another piece

This issue is divided into eight stages, followed by the eight pieces into the first row, second row, ......, the eighth row, in the process of placement, the non-stop to check whether the rule is satisfied, if it satisfies the jump The next line continue to place the pieces, it does not meet the law try to change a discharge

int[] result = new int[8];//全局或成员变量,下标表示行,值表示queen存储在哪一列
public void cal8queens(int row){   //调用方式:cal8queen(0);
	if(row == 8){   //8个棋子都放置好了打印结果
		printQueens(result);
		return;    //8个棋子都放好了,已经没法再往下递归了,所以就return
	}
	for(int column = 0 ; column < 8 ; ++column){  //每一行都有8种放法
		if(isOk(row,column)){  //有些放法不满足要求
			result[row] = column;   //第row行的棋子放到了column列
			cal8queens(row+1);   //考察下一行
		}
	}
}

private boolean isOk(int row , int column){  //判断row行column列放置是否合适
	int leftup = column - 1 , rightup = column + 1;
	for(int i = row - 1; i >= 0 ; --i){  //逐行往上考察每一行
		if(result[i] == column) return false;  //第i行的column列有棋子吗?
		if(leftup >= 0){   //考察左上对角线:第i行leftup列有棋子吗?
			if(result[i] == leftup) return false;
		}
		if(rightup < 8 ){  //考察右上对角线:第i行rightup列有棋子吗?
			if(result[i] == rightup)  return false;
		}
		--leftup ; ++rightup;
	}
	return true;
}

private void printQueens(int[] result){   //打印出一个二维矩阵
	for(int row = 0 ; row < 8 ; ++row){
		for(int column = 0 ;; column < 8 ; ++column){
			if(result[row] == column) System.out.print("Q ");
			else System.out.print("* ");
		}
		System.out.println():
	}
	System.out.println();
}

Application of two classic backtracking algorithm

1. 0-1 backpack

A backpack, the backpack of the total weight of the carrier Wkg, we have n items, ranging from the weight of each item, and indivisible, it is desirable to select several items loaded backpack, can be loaded at no more than the weight of the premise of the backpack next, how to make the total weight of the backpack largest items?

For n items, the total installation method has 2^nspecies, remove the total weight of the closest Wkg, from the rest of the installation process, select the total weight of the closest Wkg, how can you not exhaustive repeat this 2^nkind of installation method do?

The order of priority items, the entire problem is decomposed into n stages, each stage corresponding to how a selection item, an item to be processed on the first, loaded or not loaded into selected, then the rest of the article processed recursively

If you find that the weight of items that have been selected over the Wkg, stop continue probing the rest of the article

public int maxW = Integer.MIN_VALUE;//存储背包中物品总重量的最大值
//cw表示当前已经装进去的物品的重量和; i表示考察到哪个物品了;
//w背包重量 ; items表示每个物品的重量;n表示物品个数
//假设背包可承受重量100,物品个数10,物品重量存储在数组a中,那可以这样调用函数:
//f(0,0,a,10,100)
public void f(int i , int cw, int[] items , int n , int w){
	if(cw == w || i == n ){   // cw == w表示装满了;i== n表示已经考察完所有的物品
		if(cw  >  maxW) maxW = cw;
		return;
	}
	f(i+1 , cw , items , n ,w);
	if(cw + items[i] <= w){   //已经超过可以背包承受的重量的时候,就不要再装了
	f(i+1 , cw + items[i] , items ,n , w);
	}
}

2. Regular Expressions

Regular expression, the most important is a wildcard, assuming regular expression comprises only *and ?two wildcards, wherein *any of the plurality of matching (greater than or equal 0) any character ?matches zero or an arbitrary character, how backtracking determine a given text, whether with the given regular expression matching?

You can inspect the regular expressions for each character, the time when non-wildcard, matching directly with the characters of the text, if the same processing continues down, if different, the backtracking

If you encounter a special character when, for example, *there are a variety of matching programs, will match any string of characters of text, first select a random matching scheme, continue to examine the rest of the characters

public class Pattern{
	private boolean matched = false;
	private char[] pattern;  //正则表达式
	private int plen;  //正则表达式长度
	
	public Pattern(char[] pattern , int  plen){
		this.pattern = pattern;
		this.plen = plen;
	}
	
	public boolean match(char[] text , int tlen){  //文本串及长度
		matched = false;
		rmatch(0,0,text,tlen);
		return matched;
	}
	
	private void rmatch(int ti,int pj, char[] text, int tlen){
		if(matched) return;//如何已经匹配了,就不需要继续递归了
		if(pj == plen){  //正则表达式到结尾了
			if(ti ==tlen) matched = true;//  文本串也到结尾了
			return;
		}
		if(pattern[pj] == "*"){   //*匹配任意个字符
			for(int k = 0 ; k <=  tlen-ti;++k){
				rmatch(ti+k,pj+1,text,tlen);
			}
		}else if (pattern[pj] == "?"){    //?匹配0个或者1个字符
			rmatch(ti,pj+1,text,tlen);
			rmatch(ti+1,pj+1,text,tlen);
		}else if(ti < tlen && pattern[pj] == text[ti]){   //纯字符匹配才行
			rmatch(ti+1,pj+1,text,tlen);
		}
	}
}
Published 75 original articles · won praise 9 · views 9182

Guess you like

Origin blog.csdn.net/ywangjiyl/article/details/104717884