第十六周学习总结
这周依旧处于复习状态,但是这周的事情其实是比较多的,C语言要测试,选修课要交论文,周末还要讲课~~~~~~,我很开心,忙碌使我快乐((ㄒoㄒ))
这周星期一星期二准备C语言测试(不要问我为什么准备),星期三星期四写论文,之后就是准备讲课和讲课。其实这周收获最大的时候就是准备讲课和讲课的时候。准备讲课的时候我发现我还有很多东西需要了解,通过准备的时候我也发现了很多新的东西,比如用Excel导入数据到mysql数据库中,之前都还不知道用有种操作。果然,有好多东西都是在不经意间被发掘出来的。
我讲课的内容是回溯算法和分治算法。因为分治算法其实有好多所以我只是简单地讲了一个用分治法实现二分查询,主要是讲回溯算法。
接下来就简单介绍一下我讲课的内容。
回溯算法
回溯算法中的经典问题之一就是八皇后问题,就是在8*8的棋盘上摆放8个皇后,使其不能相互攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线,问有多少种摆法。
如下图就是其中的一种摆法
我们可以把八皇后问题先简化为四皇后问题,最后再推广到N皇后如下图:
我们先按照一行一个皇后的顺序来摆,每摆一个和之前摆好的进行比较,判断是否能摆在这里,如果不行就换下一个位置,如果这一行都不行,就改变上一个棋子的位置,然后再摆,知到全部摆好。
这其实就体现了回溯算法的基本思想,当走不通的时候就退回去找另外一条路走。具体代码如下:
package main;
/**
* Created by wolf on 2019/06/16
*/
public class WolfQueen {
int max = 4; //棋盘大小及皇后数量
int[] array = new int[max]; //存储每个棋子的位置
static int num= 0; //计数器
public void check(int n){
//结束条件
if (n == max){
for (int i = 0;i<array.length;i++){
System.out.print(array[i]+1+" ");
}
System.out.println();
num++;
}else {
for (int i =0;i<max;i++){
array[n] = i;
if (judge(n)){
check(n+1);
}
}
}
}
private boolean judge(int n) {
for (int i =0;i<n;i++){
if (array[i] == array[n] || Math.abs(n-i)== Math.abs(array[n] - array[i])){
return false;
}
}
return true;
}
public static void main(String[] args) {
WolfQueen wolfQueen = new WolfQueen();
wolfQueen.check(0);
System.out.println(num);
}
}
推广到8皇后或N皇后时只要把 max 改为 8 或 N 就行了。
除此之外还有迷宫问题也可以用回溯算法很简单解决。
代码如下:
package main;
public class MiGong {
/**
* 定义迷宫数组
*/
private int[][] array = {
{0, 0, 1, 0, 0, 0, 1, 0},
{0, 0, 1, 0, 0, 0, 1, 0},
{0, 0, 1, 0, 1, 1, 0, 1},
{0, 1, 1, 1, 0, 0, 1, 0},
{0, 0, 0, 1, 0, 0, 0, 0},
{0, 1, 0, 0, 0, 1, 0, 1},
{0, 1, 1, 1, 1, 0, 0, 1},
{1, 1, 0, 0, 0, 1, 0, 1},
{1, 1, 0, 0, 0, 0, 0, 0}
};
private int maxLine = 8;
private int maxRow = 9;
public static void main(String[] args) {
new MiGong().check(0, 0);
}
private void check(int i, int j) {
//如果到达右下角出口
if (i == maxRow - 1 && j == maxLine - 1) {
array[i][j] = 5;
print();
array[i][j] = 0;
return;
}
//向右走
if (canMove(i, j + 1)) {
array[i][j] = 5;
check(i, j + 1);
array[i][j] = 0;
}
//向左走
if (canMove(i, j - 1)) {
array[i][j] = 5;
check(i, j - 1);
array[i][j] = 0;
}
//向下走
if (canMove(i + 1, j)) {
array[i][j] = 5;
check(i + 1, j);
array[i][j] = 0;
}
//向上走
if (canMove(i - 1, j)) {
array[i][j] = 5;
check(i - 1, j);
array[i][j] = 0;
}
}
private boolean canMove(int targetI, int targetJ) {
// System.out.println("从第" + (i + 1) + "行第" + (j + 1) + "列,走到第" + (targetI + 1) + "行第" + (targetJ + 1) + "列");
if (targetI < 0 || targetJ < 0 || targetI >= maxRow || targetJ >= maxLine) {
// System.out.println("到达最左边或最右边,失败了");
return false;
}
if (array[targetI][targetJ] == 1) {
// System.out.println("目标是墙,失败了");
return false;
}
//避免在两个空格间来回走
if (array[targetI][targetJ] == 5) {
// System.out.println("来回走,失败了");
return false;
}
return true;
}
private void print() {
System.out.println("得到一个解:");
for (int i = 0; i < maxRow; i++) {
for (int j = 0; j < maxLine; j++) {
System.out.print(array[i][j] + " ");
}
System.out.println();
}
}
}
如果想求最优解时,只需要比较数组中5的个数就行了。
分治算法
分治法实现二分查询
package main;
public class BinarySearch {
/**
* 普通查询
*
* @param s
* @param q
* @return
*/
public static int BrutalForceSearch(int[] s, int q) {
for (int i = 0; i < s.length; i++) {
if (q == s[i])
return i;
}
return -1;
}
/**
* f(n) = log(n)
*
* @param s
* @param q
* @return
*/
public static int DCSearch(int[] s, int q, int startIndex, int endIndex) {
if (startIndex > endIndex){
return -1;
}
else {
int mid = (startIndex + endIndex) / 2;
if (s[mid] == q){
return mid;
}
else {
if (s[mid] > q) {
return DCSearch(s, q, startIndex, mid - 1);
}
else {
return DCSearch(s, q, mid + 1, endIndex);
}
}
}
}
/**
* 不用递归的二分查询
* @param arr
* @param key
* @param low
* @param high
* @return
*/
public static int Binary(int[] arr, int key, int low, int high) {
while (low <= high) {
int mid = (low + high) / 2;
if (arr[mid] > key) {
high = mid - 1;
} else if (arr[mid] < key) {
low = mid + 1;
} else {
return mid;
}
}
return -1;
}
public static void main(String[] args) {
int [] s = new int[10000000];
for(int i = 0;i<10000000;i++){
s[i] = i;
}
int q = 10000000-156;
//对比查询时间
long startTime = System.currentTimeMillis();
System.out.println(BrutalForceSearch(s, q));
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
startTime = System.currentTimeMillis();
System.out.println(DCSearch(s, q, 0, s.length - 1));
endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
// startTime = System.currentTimeMillis();
// System.out.println(Binary(s,q,0,s.length));
// endTime = System.currentTimeMillis();
// System.out.println(endTime-startTime);
}
}