[UVa 11212] Editing a Book (迭代加深搜索)

链接

UVa 11212


题意

给出一组1到n(n < 10)的排列和一种操作“剪切粘贴”,可以选定排列的一段剪掉并且粘贴在任意其他位置形成新的排列,问最少执行几次操作可以得到排列1, 2, … n。


题解

将一个排列看做一个状态就是标准的宽搜题,9!并不大,但是后继状态特别多,宽搜肯定是妥妥地超时。
迭代加深搜索,如刘汝佳所说是一个“长期以来被低估的算法”,它由于限定了深度maxd,给搜索过程提供了剪枝的可能,效率上大大优化了。


代码

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n, maxd, v[10][10];
inline int badx(const int s[]) {
    int ret = 0; for(int i = 0; i < n-1; i++) ret += int(s[i + 1] != s[i] + 1); return ret;
}
bool IDAstar(int cur)
{
    if(cur == maxd) {
        for(int i = 0; i < n-1; i++) if(v[cur][i] + 1 != v[cur][i + 1]) return false; return true;
    }
    if(badx(v[cur]) - 3 * (maxd - cur) > 0) return false;
    for(int l = 0; l < n; l++) {
        for(int r = l; r < n; r++) {
            if(r - l + 1 == n) break;
            if(l > 0 && v[cur][l-1] + 1 == v[cur][l] || r < n-1 && v[cur][r] + 1 == v[cur][r+1]) continue;
            for(int k = 0; k < n; k++) if(k < l || k > r + 1) {
                for(int i = 0, m = 0; i < n; i++) {
                    if(i >= l && i <= r) continue;
                    if(i == k) for(int j = l; j <= r; j++) v[cur + 1][m++] = v[cur][j];
                    v[cur + 1][m++] = v[cur][i];
                }
                if(IDAstar(cur + 1)) return true;
            }
        }
    }
    return false;
}

int main()
{
    //freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
    int kase = 0;
    while(cin >> n) { if(0 == n) break;
        for(int i = 0; i < n; i++) scanf("%d", &v[0][i]);
        printf("Case %d: ", ++kase);
        bool ok = true; for(int i = 0; i < n-1; i++)
        if(v[0][i] + 1 != v[0][i+1]) { ok = false; break; }
        if(ok) { printf("0\n"); continue; }
        for(maxd = 1; maxd < n; maxd++)
        if(IDAstar(0)) { printf("%d\n", maxd); break; }
    }
    return 0;
}

你可能感兴趣的:([UVa 11212] Editing a Book (迭代加深搜索))