八数码(IDA*)

IDA*+曼哈顿 相当快! 通过五组数据总计用时 0.015000 s.

把宏定义中的N和SIZE改一下,就可以处理十五数码问题了,终于修炼到第八层了;

刚开始还是使用结构体定义了状态,写得相当麻烦,后来发现IDA*中不像BFS和A*,只需要考虑一条路,,参考了lym(http://www.cnblogs.com/liyongmou/archive/2010/07/19/1780861.html)的(后面调试的受不了了,对照着此大牛的代码一点点改,最后发现是更新状态时,npos写成了pos……)

# include <stdio.h>
# include <math.h>
# include <string.h>
# include <time.h>

# define MIN(x, y) ((x)<(y) ? (x):(y))

# define N 9
# define DIR_N 4
# define INF 0x7fffffff
# define MAX_DEPTH 1000
# define SIZE 3

char solved;
char start[N], goal[N];
char cur[N];

int bound;
const char md[] = {'u', 'l', 'r', 'd'};
const short int dir[][2] = {{-1,0}, {0,-1}, {0,1}, {1,0}};
char path[MAX_DEPTH];

void move(void);
void solve(void);
char read(char *s);
int IDAstar(void);
char bool_inv(char *s);
int heu(void);
int dfs(int zero_pos, int depth, char direction);
void print_state(char *s);

int main()
{
         freopen("in.txt", "r", stdin);
         freopen("out.txt", "w", stdout);

    while (read(start))
    {
        read(goal);
        memcpy(cur, start, N);
        solve();
    }
    
    printf("time cost %.6lf s.\n", (double)clock()/CLOCKS_PER_SEC);

    return 0;
}

void solve()
{
    int i, depth;

    if (bool_inv(start) != bool_inv(goal)) puts("unsolvable");
    else
    {
        memset(path, -1, sizeof(path));
        depth = IDAstar();
        for (i = 0; path[i]!=-1; ++i)
        {
            putchar(md[path[i]]);
        }
        printf(" %d\n", i);
    }
    //move(); //打印移动过程,调试的时候用的,加上这个总共用时31ms
}

char read(char *s)
{
    char c[5];
    int i;

    if (EOF == scanf("%s", c)) return 0;
    else s[0] = (c[0]=='x' ? 0:c[0]-'0');
    for (i = 1; i < N; ++i)
    {
        scanf("%s", c);
        s[i] = (c[0]=='x' ? 0:c[0]-'0');
    }
    
    return 1;
}

int IDAstar(void)
{
    int i;

    solved = 0;
    bound = heu();

    for (i = 0; start[i] && i < N; ++i) ;

    while (!solved && bound<100)
    {
        bound = dfs(i, 0, -10);
    }

    return bound;
}

int dfs(int pos, int depth, char d)
{
    int h, i, nx, ny, npos, nbound, t;

    h = heu();

    if (depth+h > bound) return depth+h;
    if (h == 0)
    {
       /* printf("depth = %d.\n", depth); */
        solved = 1;
        return depth;
    }

    nbound = INF;
    for (i = 0; i < DIR_N; ++i)
    {
        if (i+d == DIR_N-1) continue;
        nx = pos/SIZE + dir[i][0];
        ny = pos%SIZE + dir[i][1];
        if (0<=nx && nx<SIZE && 0<=ny && ny<SIZE)
        {
            path[depth] = i;
            npos = nx*SIZE + ny;
            cur[pos] = cur[npos]; cur[npos] = 0;    /* 后来一直出错就是这里的原因:pos -> npos */
            t = dfs(npos, depth+1, i);
            if (solved) return t;
            nbound = MIN(nbound, t);
            cur[npos] = cur[pos]; cur[pos] = 0;
        }
    }
    return nbound;
}

int heu(void)            /* return heu(cur_state) */
{
    char ch;
    int i, j, ret;

    ret = 0;
    for (i = 0; i < N; ++i)
    {
        ch = goal[i];
        if (ch == 0) continue;
        for (j = 0; j < N; ++j)
        {
            if (ch == cur[j])
            {
                ret = ret + abs(i/SIZE-j/SIZE) + abs(i%SIZE-j%SIZE);
            }
        }
    }

    return ret;
}

char bool_inv(char *s)
{
    char ch, ret;
    int i, j;

    ret = 0;
    for (i = 0; i < N-1; ++i)
    {
        if ((ch = s[i]) == 0) continue;
        for (j = i+1; j < N; ++j)
        {
            if (s[j] && s[j]<ch) ret = 1 - ret;
        }
    }

    return ret;
}

void move(void)
{
    char ncur[N];
    int i, pos, nx, ny, npos;

    memcpy(ncur, start, N);
    print_state(ncur);
    for (i = 0; start[i] && i<N; ++i) ;
    pos = i;
    for (i = 0; path[i] != -1; ++i)
    {
        nx = pos/SIZE + dir[path[i]][0];
        ny = pos%SIZE + dir[path[i]][1];
        npos = nx*SIZE + ny;
        ncur[pos] = ncur[npos]; ncur[npos] = 0;
        pos = npos;
        print_state(ncur);
    }
}

void print_state(char *s)
{
    int i;

    for (i = 0; i < N; ++i)
    {
        putchar(s[i]+'0');
    }
    putchar('\n');
}

//

原文地址:https://www.cnblogs.com/JMDWQ/p/2519728.html