POJ 3460 Booksort (IDA*)

只能说这题的估价函数太神了.............黑书的思想一直很牛X

题意:有一个 1--n的序列,顺序打乱了,目标是要让每个数字在对应的位置(1对应1.......),移动的时候取连续的一段与左边或者右边的某一段交换位置(一段也可以是一个数值)。

分析:摘自黑书:本题和传统的八数码问题有类似之处,但是其启发函数不好找。如果也是把所有段落的曼哈顿距离作为估价值,则h函数是不相容的,一次移动可能让所有段落离家距离减少很多(不是线性的)。

移动是以连续段落为整体的,启发我们设计一个“相对位置”的h函数,例如h = “后继段落正确的段落数目”。显然假设把段落S从P1后面移动到P2后面,则有1.S的最后一个段落    2.

P1   3.P2   三个段落后继有变化。每次最多减少3,。常熟级别了。所以把估价函数扩大三倍f = h + 3 * step 就是线性的了。

这里取的是后继段落中错误的段落数目..............所以h == 0 的时候,找到了解。


#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <climits>//形如INT_MAX一类的
#define MAX 100005
#define INF 0x7FFFFFFF
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define L(x) x<<1
#define R(x) x<<1|1
# define eps 1e-5
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std;

int a[20],n,limit;
int ans;
int h(int a[]) {
    int v = 0;
    if (a[1] != 1) v++;
    for (int i=1; i<n; i++)
        if (a[i+1] != a[i]+1) v++;
    return v;
}
void trans(int *a,int p1,int p2,int p3) {
    int tmp[20];
    for (int i=p1; i<=p2; i++)
        tmp[i] = a[i];
    for (int i=p2+1; i<=p3; i++)
        a[i-p2+p1-1] = a[i];
    for (int i=p1+p3-p2; i<=p3; i++)
        a[i] = tmp[i+p2-p3];
}
int dfs(int *a,int dep) {
    int hv = h(a);
    if (hv == 0) {
        ans = 1;
        return dep;
    }
    if (hv + 3 * dep > limit) return hv + 3 * dep;
    int minn = 11111;
    for (int i=1; i<n; i++)
        for (int j=i+1; j<=n; j++) //交换i,k区间和k,j区间
            for (int k=i; k<j; k++) {
                int tmp[20];
                for (int r=1; r<=n; r++) tmp[r] = a[r];
                trans(tmp,i,k,j);
                int t = dfs(tmp,dep+1);
                if (ans) return t;
                minn = min(minn,t);
            }
    return minn;
}
void IDA_star() {
    limit = h(a);
    ans = 0;
    while (!ans && limit <= 12)
        limit = dfs(a,0);
    if (ans) printf("%d\n",limit);
    else printf("5 or more\n");
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d",&n);
        for (int i=1; i<=n; i++)
            scanf("%d",&a[i]);

        if (h(a) == 0) {
            printf("0\n");
            continue;
        }
        IDA_star();
    }
    return 0;
}


你可能感兴趣的:(POJ 3460 Booksort (IDA*))