【题目链接】点击打开链接
【题意】 可以看紫书 208 页,比较难写就不介绍了。
【解题思路】本题利用迭代加深搜索,也是一道典型的状态空间搜索问题,状态就是1~n的排列,初始状态是输入,终止状态是1,2,……n。由于n≤9,排列最多有9!=362880个,但由于每个状态的后继状态比较多,因此仍有TLE的危险。本题如果利用迭代加深搜索,可以发现做多只需要8步,关键在于如何有效地剪枝。考虑后继不正确的数字的个数h,可以证明每次剪切时h最多减少3(因为一次剪切最多只会改变3个数字的后继,若剪切后这3个数字的后继都正确,则h最多减少了3),因此当h>3*(maxd-d)时剪枝即可。
估价函数是IDA*搜索的核心!
【AC代码】
//
//Created by BLUEBUFF 2016/1/8
//Copyright (c) 2016 BLUEBUFF.All Rights Reserved
//
#pragma comment(linker,"/STACK:102400000,102400000")
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <time.h>
#include <cstdlib>
#include <cstring>
#include <sstream> //isstringstream
#include <iostream>
#include <algorithm>
using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int, LL> pp;
#define REP1(i, a, b) for(int i = a; i < b; i++)
#define REP2(i, a, b) for(int i = a; i <= b; i++)
#define REP3(i, a, b) for(int i = a; i >= b; i--)
#define CLR(a, b) memset(a, b, sizeof(a))
#define MP(x, y) make_pair(x,y)
const int maxn = 12;
const int maxm = 2e5;
const int maxs = 10;
const int maxp = 1e3 + 10;
const int INF = 1e9;
const int UNF = -1e9;
const int mod = 1e9 + 7;
//int gcd(int x, int y) {return y == 0 ? x : gcd(y, x % y);}
//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
//head
int a[maxn], maxd, n;
struct node{
int v[maxn];
};
int cal(int *a){ //计算后继不正确的个数
int cnt = 0;
for(int i = 0; i < n; i++){
if(a[i] + 1 != a[i + 1])
cnt++;
}
return cnt;
}
void moveTo(node &s, node &t, int i, int j, int k){ //t是移动之后的
int num = j - i + 1; //要移动的个数
for(int u = 0; u < num; u++){ //把原来 i, j 之间的数移动到 k 后面
t.v[k + u] = s.v[i + u];
}
num = i - k;
for(int u = 0; u < num; u++){ //把原来 k, i 之间的数移动到k + j - i后面
t.v[j - u] = s.v[i - 1 - u];
}
}
bool dfs(int d, node t){
if(cal(t.v) > 3 * (maxd - d)) return false;
if(cal(t.v) == 0) return true;
node nxt;
for(int i = 0; i < n; i++){
for(int j = i; j < n; j++){
for(int k = 0; k < i; k++){
memcpy(nxt.v, t.v, sizeof(t.v));
moveTo(t, nxt, i, j, k);
if(dfs(d + 1, nxt)) return true;
}
}
}
return false;
}
int main()
{
int ks = 0;
while(scanf("%d", &n) != EOF && n)
{
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
a[n] = n + 1;
int cur = 0;
cur = cal(a);
node x;
memcpy(x.v, a, sizeof(a));
if(cur){
for(maxd = 1;; maxd++){
if(dfs(0, x)){
break;
}
}
}
printf("Case %d: ", ++ks);
if(cur == 0) maxd = 0;
printf("%d\n", maxd);
}
return 0;
}