IDA* 解八数码问题: POJ 1077

刚刚学IDA*,再来写一遍八数码问题。又一次见证了别人家的代码和自己的代码的差距。

别人家的链接:http://www.xuebuyuan.com/1863051.html

h函数自己一开始写的是不在正确位置上的数码的个数,性能低下,T。
更优的一个,也是很多人用的一个就是所有数码与正确位置的曼哈顿距离之和。
然而自己写这个还是T,看了别人家的代码中有个小剪枝,加上后用C++编译还是T,使用G++,1000Ms过。真是压线。
人家的是0Ms。

注:所说的小剪枝是相邻的两步不来回走,在原博客中有代码因为长度过长导致一部分没有显示出来粘贴到Dev上注释会变成乱码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

int maxd, mi = 100, beg[10], n[10];
char ans[105];

int h(){
    int res = 0;
    for(int i = 1; i <= 9; i++){
        if(n[i] < 9){
            int x = (i-1)/3 + 1;
            int y = i % 3; if(!y) y = 3;
            int x2 = (n[i]-1)/3 + 1;
            int y2 = n[i] % 3; if(!y2) y2 = 3;
            res += abs(x-x2)+abs(y-y2);
        }
    }
    mi = min(mi, res);
    return res;
}

bool dfs(int ed){
    if(!h()){
        ans[ed] = '\0';
        printf("%s\n", ans);
        return 1;
    }
    if(ed + h() >= maxd) return 0;
    int pos = 0;
    while(n[pos] < 9) pos++;
    if(pos % 3){
        swap(n[pos], n[pos+1]);
        ans[ed] = 'r';
        if(dfs(ed+1)) return 1;
        swap(n[pos], n[pos+1]);
    }
    if(pos <= 6){
        swap(n[pos], n[pos+3]);
        ans[ed] = 'd';
        if(dfs(ed+1)) return 1;
        swap(n[pos], n[pos+3]);
    }
    if(pos > 3){
        swap(n[pos], n[pos-3]);
        ans[ed] = 'u';
        if(dfs(ed+1)) return 1;
        swap(n[pos], n[pos-3]);
    }
    if(pos % 3 != 1){
        swap(n[pos], n[pos-1]);
        ans[ed] = 'l';
        if(dfs(ed+1)) return 1;
        swap(n[pos], n[pos-1]);
    }
    return 0;
}

int main()
{
    for(int i = 1; i <= 9; i++){
        char s[2]; scanf("%s", s);
        if(s[0] != 'x') beg[i] = s[0] - 48;
        else beg[i] = 9;
    }   

    int ni = 0;
    for(int i = 1; i < 9; i++)
    for(int j = i+1; j <= 9; j++){
        ni += beg[i] > beg[j] && beg[i] != 9;
    }
    if(ni&1){
        puts("unsolvable");
        return 0;
    }

    for(maxd = h(); ; maxd+=mi){
        for(int i = 1; i <= 9; i++) n[i] = beg[i];
        if(dfs(0)) return 0;
    }
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值