分治算法概念
分治即分而治之。一个问题规模过大不容易直接解决,就可以划分成许多小问题,如果小问题不容易求解,那么可以再划分成规模更小的问题,直到规模小到很容易解决为止,解决这些小问题,再将小问题的解合并成大问题的解。这就是分治算法的基本思想。
至于小问题的规模到底划分多大,这是没有规定的,依实际情况而定。小问题的规模可以是相等的,也可以是不相等的。可以分成简单的2个小问题,当然也可以分成多个小问题。
分治算法常用的实现方法是递归。因为分治就是将大问题不断划分成小问题,递归的解决小问题,再合并小问题的解就可以得到问题的解。
递归
递归,就是在函数内部调用本函数自身。形式如下
void foo()
{
//...
foo(); //递归
//...
}
经典问题
(1)二分搜索
public class Main{
/**
* 在数组a中查找tag,返回其坐标
* @param a
* @param tag
* @return
*/
public static int binarySearch(int[] a,int tag){
if(a == null || a.length == 0){
return -1;
}
int low = 0,hight = a.length-1,mid = 0;
while(low<=hight){
mid = (low+hight)/2;
// 正好是中间的元素
if(tag == a[mid]){
return mid;
}else if(tag<a[mid]){
hight = mid-1;
}else{
low = mid+1;
}
}
return -1;
}
public static void main(String[] args){
int[] arr = new int[]{0,1,2,3,4,5,6,7,8,9};
System.out.println(binarySearch(arr,22));
}
}
(2)大整数乘法
(3)Strassen矩阵乘法
(4)棋盘覆盖
一、问题描述
二、过程详解
1、棋盘如下图,其中有一特殊方格:16*16
2、第一个分割结果:88
3、第二次分割结果:44
4、第三次分割结果:22
5、第四次分割结果:11
6、第一次分割后子棋盘的覆盖效果
三、代码实现
public class Main {
// 定义棋盘的大小:2^k,需要的骨牌数是:(4^k-1)/3
private static int BOARD_SIZE = 8;
// 定义一个二维数组用来模拟棋盘
private static int[][] board = new int[BOARD_SIZE][BOARD_SIZE];
// 定义一个全局变量,用来记录骨牌的编号
private static int tile = 0;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("棋盘的大小为:" + BOARD_SIZE);
System.out.println("请输入特殊方格所在的行号:");
int dr = scanner.nextInt();
System.out.println("请输入特殊方格所在的列号:");
int dc = scanner.nextInt();
scanner.close();
// 行号和列号与二位数组的下标相差 1
chessBoard(0, 0, dr - 1, dc - 1, BOARD_SIZE);
System.out.println("特殊方块在第 " + dr + " 行第 " + dc + "列,覆盖后的棋盘:");
// 输出棋盘
printBoard();
}
/**
* 覆盖棋盘:tr、tc、dt、dc从0开始
* @param tr:棋盘左上角方格的行号
* @param tc:棋盘左上角方格的列号
* @param dr:特殊方格所在的行号
* @param dc:特殊方格所在的列号
* @param size:当前棋盘的大小
*/
private static void chessBoard(int tr, int tc, int dr, int dc, int size) {
if(size == 1){
return;
}
int t = tile++;
// 分割棋盘
int s = size / 2;
// 1、如果特殊方格在棋盘左上角
if(dr < tr+s && dc < tc+s){
// 对左上角的棋盘进行覆盖
chessBoard(tr,tc,dr,dc,s);
}else{
// 如果特殊方格不在左上角的子棋盘中,用 t 号骨牌覆盖该子棋盘的右下角作为特殊方格
board[tr+s-1][tc+s-1] = t;
// 覆盖其余方格
chessBoard(tr,tc,tr+s-1,tc+s-1,s);
}
// 2、如果特殊方格在棋盘左下角
if(dr > tr+s-1 && dc < tc+s){
// 对左下角的棋盘进行覆盖
chessBoard(tr+s,tc,dr,dc,s);
}else{
// 如果特殊方格不在左下角的子棋盘中,用 t 号骨牌覆盖该子棋盘的右上角作为特殊方格
board[tr+s][tc+s-1] = t;
// 覆盖其余方格
chessBoard(tr+s,tc,tr+s,tc+s-1,s);
}
// 3、如果特殊方格在棋盘右上角
if(dr < tr+s && dc > tc + s -1){
// 对右上角的棋盘进行覆盖
chessBoard(tr,tc+s,dr,dc,s);
}else{
// 如果特殊方格不在右上角的子棋盘中,用 t 号骨牌覆盖该子棋盘的左下角作为特殊方格
board[tr+s-1][tc+s] = t;
// 覆盖其余方格
chessBoard(tr,tc+s,tr+s-1,tc+s,s);
}
// 4、如果特殊方格在棋盘右下角
if(dr > tr+s-1 && dc > tc+s-1){
// 对右下角的棋盘进行覆盖
chessBoard(tr+s,tc+s,dr,dc,s);
}else{
// 如果特殊方格不在右下角的子棋盘中,用 t 号骨牌覆盖该子棋盘的左上角作为特殊方格
board[tr+s][tc+s] = t;
// 覆盖其余方格
chessBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
// 输出棋盘
private static void printBoard() {
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
System.out.print(board[i][j] + "\t");
}
System.out.println("\n");
}
}
}