题目描述:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23956
/*
solution:
采用IDA*算法
note:
IDA*算法就是从小到大枚举深度上限,每次执行只考虑最大深度之内的结点,再设计一个乐观估价函数,用来剪枝。
其实就是 “迭代加深搜索” + "乐观函数剪枝"
date:
2016/5/8
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 10;
int n, book[maxn];
bool is_goal() {
bool ok = true;
for(int i = 0; i < n; i++) {
if(book[i] != i + 1) {
ok = false;
break;
}
}
return ok;
}
int h() {
int cnt = 0;
for(int i = 0; i < n - 1; i++) {
if(book[i] + 1 != book[i + 1])
cnt++;
}
if(book[n - 1] != n) cnt++;
return cnt;
}
bool dfs(int d, int maxd) {
if(3 * d + h() > maxd * 3) return false; //剪枝
if(is_goal()) return true;
//扩展节点同时进行加深搜索
int old_book[maxn]; //因为扩展节点后book会随之改变,为了保存原来的book
int past_to[maxn]; //保存要剪切后的部分
for(int i = 0; i < n; i++)
for(int j = i; j < n; j++) { //依次枚举要剪切的部分,i是左端开头,j是右端结尾
memcpy(old_book, book, sizeof(book)); //保存原来book
int cnt = 0;
for(int k = 0; k < n; k++)
if(k < i || k > j)
past_to[cnt++] = book[k]; //剪切后的部分
for(int k = 0; k <= cnt; k++) { //依次枚举要插入第k位置前面
int cnt2 = 0; //执行粘贴操作
for(int p = 0; p < k; p++) book[cnt2++] = past_to[p];
for(int p = i; p <= j; p++) book[cnt2++] = old_book[p];
for(int p = k; p < cnt; p++) book[cnt2++] = past_to[p];
if(dfs(d + 1, maxd)) return true; //加深搜索
memcpy(book, old_book, sizeof(old_book)); //如果加深搜索失败的话就返回原来的数组状态
}
}
return false;
}
int solve() {
if(is_goal()) return 0;
for(int maxd = 0; maxd < 9; maxd++) //枚举层数,最多不超过9层dfs即可求出答案
if(dfs(0, maxd)) return maxd;
return -1;
}
int main()
{
//freopen("input.txt", "r", stdin);
int kase = 0;
while(~scanf("%d", &n) && n) {
memset(book, 0, sizeof(book));
for(int i = 0; i < n; i++) scanf("%d", &book[i]);
printf("Case %d: %d\n", ++kase, solve());
}
return 0;
}