问题导读:
假设有n块大小不一的烙饼,翻烙饼时只能从最上面的烙饼开始,一次抓住最上面的几块饼,把它们上下颠倒个儿,那么最少要翻多少次,才能够达到最后的大小有序?得到一个解决方案。
解决方案:
package Chapter1;
import java.util.*;
/*
烙饼排序(寻找最优翻转方案):
1. 将本应该相邻的两个烙饼尽可能的翻转到一起
2. 当前步数 + 估算这次搜索所需要下界步数 < 最多交换次数
*/
public class Func_1_3_1 {
int []cake_arr; //烙饼信息数组
int cake_cnt; // 烙饼个数
int max_swap; //最多交换次数
int []swap_arr; //烙饼交换结果数组
int []reverse_cake_arr; // 当前翻转 烙饼信息数组
int []reverse_cake_swap_arr; //当前翻转 烙饼交换结果数组
int n_search; // 当前搜索次数
public Func_1_3_1(int []cake_arr, int cake_cnt) {
this.cake_arr = cake_arr;
this.cake_cnt = cake_cnt;
this.max_swap = upperBound(cake_cnt);
this.swap_arr = new int[this.max_swap + 1];
this.reverse_cake_arr = new int[cake_cnt];
for (int i = 0; i<cake_cnt; i++) {
this.reverse_cake_arr[i] = this.cake_arr[i];
}
this.reverse_cake_swap_arr = new int[this.max_swap];
this.n_search = 0;
}
// 得到上界
int upperBound(int cake_cnt) {
/*
1. 最大的在倒数第二位,将它翻到第一位
2. 再将最上的(最大的)翻到最后一位
3. 最后,最小的自然在上,不用翻,
4. 2*(n-1)
*/
return (cake_cnt-1) * 2;
}
// 得到下界
int lowerBound(int []cake_arr, int cake_cnt) {
int flag, ret = 0;
for (int i = 1; i < cake_cnt; i++) {
flag = cake_arr[i] - cake_arr[i];
if (flag != 1 && flag != -1) {
ret++;
}
}
return ret;
}
// 翻转烙饼
void reverse(int n_begin, int n_end) {
if (n_begin > n_end)
return;
int i, j;
for(i = n_begin, j = n_end; i<j; i++, j--) {
this.reverse_cake_arr[i] = this.reverse_cake_arr[i] + this.reverse_cake_arr[j] -
(this.reverse_cake_arr[j] = this.reverse_cake_arr[i]);
}
}
// 判断是否已经排序完成
boolean isSorted(int []cake_arr, int cake_cnt) {
for (int i = 1; i<cake_cnt; i++) {
if (cake_arr[i] < cake_arr[i-1]) {
// 下面的小于上面的,false
return false;
}
}
return true;
}
// 深搜
// 省空间,不一定是最优解
// 重在剪枝
void dfs(int step) {
int n_estimate;
this.n_search++;
n_estimate = lowerBound(this.reverse_cake_arr, this.cake_cnt);
// 步数大于上界
if (step + n_estimate > this.max_swap)
return;
// 如果排序完成
if (isSorted(this.reverse_cake_arr, this.cake_cnt)) {
if (step < this.max_swap) {
this.max_swap = step;
for (int i = 0; i<this.max_swap; i++)
this.swap_arr[i] = this.reverse_cake_swap_arr[i];
}
return;
}
// 递归进行翻转
for (int i = 1; i<cake_cnt; i++) {
reverse(0, i);
this.reverse_cake_swap_arr[step] = i;
dfs(step + 1);
reverse(0, i);
}
}
// 输出
void outPut() {
System.out.println();
System.out.println(Arrays.toString(this.swap_arr));
System.out.println("搜索次数: " + this.n_search + "\n步数: " + this.max_swap);
}
public static void main(String []args) {
int []arr = {4, 2, 1, 3};
Func_1_3_1 f = new Func_1_3_1(arr, 4);
f.dfs(0);
f.outPut();
}
}
参考博文:
dfs(x,y,step)
if visited
if ok
for:dfs(x,y,step+1)
bfs()
queue.offer
while(queue.isNotEmpty):
queue.poll
if ok
for:queue.offer