【题目链接】点击打开链接

【题意】 可以看紫书 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;
}