poj 1077 Eight (BFS)

八数码问题,各种解法。


/*
// BFS
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;

// 把1..n的排列映射为数字 0..(n!-1)
int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };//...
int order(const char *s, int n) {
    int i, j, temp, num;

    num = 0;

    for (i = 0; i < n-1; i++) {
        temp = 0;
        for (j = i + 1; j < n; j++) {
            if (s[j] < s[i])
                temp++;
        }
        num += fac[s[i] -1] * temp;
    }
    return num;
}

bool is_equal(const char *b1, const char *b2){
    for(int i=0; i<9; i++)
        if(b1[i] != b2[i])
            return false;
    return true;
}


//hash
struct node{
    char board[9];
    char space;//空格所在位置
};

const int TABLE_SIZE = 362880;

int hash(const char *cur){
    return order(cur, 9);
}

// 整数映射成排列
void get_node(int num, node &tmp) {
    int n=9;
    int a[9]; //求逆序数
    for (int i = 2; i <= n; ++i) {
        a[i - 1] = num % i;
        num = num / i;
        tmp.board[i - 1] = 0;//初始化
    }
    tmp.board[0] = 0;
    int rn, i;
    for (int k = n; k >= 2; k--) {
        rn = 0;
        for (i = n - 1; i >= 0; --i) {
            if (tmp.board[i] != 0)
                continue;
            if (rn == a[k - 1])
                break;
            ++rn;
        }
        tmp.board[i] = k;
    }
    for (i = 0; i < n; ++i)
        if (tmp.board[i] == 0) {
            tmp.board[i] = 1;
            break;
        }
    tmp.space = n - a[n-1] -1;
}

char visited[TABLE_SIZE];
int parent[TABLE_SIZE];
char move[TABLE_SIZE];
int step[4][2] = {{-1, 0},{1, 0}, {0, -1}, {0, 1}};//u, d, l, r

void BFS(const node & start){
    int x, y, k, a, b;
    int u, v;

    for(k=0; k<TABLE_SIZE; ++k)
        visited[k] = 0;
    u = hash(start.board);
    parent[u] = -1;
    visited[u] = 1;

    queue<int> que;
    que.push(u);

    node tmp, cur;
    while(!que.empty()){
        u = que.front();
        que.pop();

        get_node(u, cur);

        k = cur.space;
        x = k / 3;
        y = k % 3;
        for(int i=0; i<4; ++i){
            a = x + step[i][0];
            b = y + step[i][1];
            if(0<=a && a<=2 && 0<=b && b<=2){
                tmp = cur;
                tmp.space = a*3 + b;
                swap(tmp.board[k], tmp.board[tmp.space]);
                v = hash(tmp.board);
                if(visited[v] != 1){
                    move[v] = i;
                    visited[v] = 1;
                    parent[v] = u;
                    if(v == 0) //目标结点hash值为0
                        return;

                    que.push(v);
                }
            }
        }
    }
}

void print_path(){
    int n, u;
    char path[1000];
    n = 1;
    path[0] = move[0];
    u = parent[0];
    while(parent[u] != -1){
        path[n] = move[u];
        ++n;
        u = parent[u];
    }
    for(int i=n-1; i>=0; --i){
        if(path[i] == 0)
            printf("u");
        else if(path[i] == 1)
            printf("d");
        else if(path[i] == 2)
            printf("l");
        else
            printf("r");
    }
}

int main(){
//    freopen("in", "r", stdin);

    node start;
    char c;
    for(int i=0; i<9; ++i){
        cin>>c;
        if(c == 'x'){
            start.board[i] = 9;
            start.space = i;
        }
        else
            start.board[i] = c - '0';
    }
    BFS(start);

    if(visited[0] == 1)
        print_path();
    else
        printf("unsolvable");
    return 0;
}

// A*
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;

// 把1..n的排列映射为数字 0..(n!-1)
int fac[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880 };//...
int order(const char *s, int n) {
    int i, j, temp, num;

    num = 0;

    for (i = 0; i < n-1; i++) {
        temp = 0;
        for (j = i + 1; j < n; j++) {
            if (s[j] < s[i])
                temp++;
        }
        num += fac[s[i] -1] * temp;
    }
    return num;
}

bool is_equal(const char *b1, const char *b2){
    for(int i=0; i<9; i++)
        if(b1[i] != b2[i])
            return false;
    return true;
}


//hash
struct node{
    char board[9];
    char space;//空格所在位置
};

const int TABLE_SIZE = 362880;

int hash(const char *cur){
    return order(cur, 9);
}

// 整数映射成排列
void get_node(int num, node &tmp) {
    int n=9;
    int a[9]; //求逆序数
    for (int i = 2; i <= n; ++i) {
        a[i - 1] = num % i;
        num = num / i;
        tmp.board[i - 1] = 0;//初始化
    }
    tmp.board[0] = 0;
    int rn, i;
    for (int k = n; k >= 2; k--) {
        rn = 0;
        for (i = n - 1; i >= 0; --i) {
            if (tmp.board[i] != 0)
                continue;
            if (rn == a[k - 1])
                break;
            ++rn;
        }
        tmp.board[i] = k;
    }
    for (i = 0; i < n; ++i)
        if (tmp.board[i] == 0) {
            tmp.board[i] = 1;
            break;
        }
    tmp.space = n - a[n-1] -1;
}

//启发函数: 除去x之外到目标的网格距离和
int goal_state[9][2] = {{0,0}, {0,1}, {0,2},
        {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2}};
int h(const char *board){
    int k;
    int hv = 0;
    for(int i=0; i<3; ++i)
        for(int j=0; j<3; ++j){
            k = i*3+j;
            if(board[k] != 9){
                hv += abs(i - goal_state[board[k]-1][0]) +
                        abs(j - goal_state[board[k] -1][1]);
            }
        }
    return hv;
}

int f[TABLE_SIZE], d[TABLE_SIZE];//估计函数和深度

//优先队列的比较对象
struct cmp{
    bool operator () (int u, int v){
        return f[u] > f[v];
    }
};
char color[TABLE_SIZE];//0, 未访问;1, 在队列中,2, closed
int parent[TABLE_SIZE];
char move[TABLE_SIZE];
int step[4][2] = {{-1, 0},{1, 0}, {0, -1}, {0, 1}};//u, d, l, r

void A_star(const node & start){
    int x, y, k, a, b;
    int u, v;
    priority_queue<int, vector<int>, cmp> open;
    memset(color, 0, sizeof(char) * TABLE_SIZE);

    u = hash(start.board);
    parent[u] = -1;
    d[u] = 0;
    f[u] = h(start.board);
    open.push(u);
    color[u] = 1;

    node tmp, cur;
    while(!open.empty()){
        u = open.top();
        if(u == 0)
            return;
        open.pop();

        get_node(u, cur);

        k = cur.space;
        x = k / 3;
        y = k % 3;
        for(int i=0; i<4; ++i){
            a = x + step[i][0];
            b = y + step[i][1];
            if(0<=a && a<=2 && 0<=b && b<=2){
                tmp = cur;
                tmp.space = a*3 + b;
                swap(tmp.board[k], tmp.board[tmp.space]);
                v = hash(tmp.board);
                if(color[v] == 1 && (d[u] + 1) < d[v]){//v in open
                    move[v] = i;
                    f[v] = f[v] - d[v] + d[u] + 1;//h[v]已经求过
                    d[v] = d[u] + 1;
                    parent[v] = u;
                    //直接插入新值, 有冗余,但不会错
                    open.push(v);
                }
                else if(color[v] == 2 && (d[u]+1)<d[v]){//v in closed
                    move[v] = i;
                    f[v] = f[v] - d[v] + d[u] + 1;//h[v]已经求过
                    d[v] = d[u] + 1;
                    parent[v] = u;
                    open.push(v);
                    color[v] = 1;
                }
                else if(color[v] == 0){
                    move[v] = i;
                    d[v] = d[u] + 1;
                    f[v] = d[v] + h(tmp.board);
                    parent[v] = u;
                    open.push(v);
                    color[v] = 1;
                }
            }
        }
        color[u] = 2; //
    }
}

void print_path(){
    int n, u;
    char path[1000];
    n = 1;
    path[0] = move[0];
    u = parent[0];
    while(parent[u] != -1){
        path[n] = move[u];
        ++n;
        u = parent[u];
    }
    for(int i=n-1; i>=0; --i){
        if(path[i] == 0)
            printf("u");
        else if(path[i] == 1)
            printf("d");
        else if(path[i] == 2)
            printf("l");
        else
            printf("r");
    }
}

int main(){
    //freopen("in", "r", stdin);

    node start;
    char c;
    for(int i=0; i<9; ++i){
        cin>>c;
        if(c == 'x'){
            start.board[i] = 9;
            start.space = i;
        }
        else
            start.board[i] = c - '0';
    }
    A_star(start);

    if(color[0] != 0)
        print_path();
    else
        printf("unsolvable");
    return 0;
}

// IDA*
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;

#define    SIZE 3

char board[SIZE][SIZE];

//启发函数: 除去x之外到目标的网格距离和
int goal_state[9][2] = {{0,0}, {0,1}, {0,2},
        {1,0}, {1,1}, {1,2}, {2,0}, {2,1}, {2,2}};
int h(char board[][SIZE]){
    int cost = 0;
    for(int i=0; i<SIZE; ++i)
        for(int j=0; j<SIZE; ++j){
            if(board[i][j] != SIZE*SIZE){
                cost += abs(i - goal_state[board[i][j]-1][0]) +
                        abs(j - goal_state[board[i][j]-1][1]);
            }
        }
    return cost;
}

int step[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};//u, l, r, d
char op[4] = {'u', 'l', 'r', 'd'};

char solution[1000];
int bound;     //上界
bool ans;    //是否找到答案
int DFS(int x, int y, int dv, char pre_move){// 返回next_bound
    int hv = h(board);
    if(hv + dv > bound)
        return dv + hv;
    if(hv == 0){
        ans = true;
        return dv;
    }

    int next_bound = 1e9;
    for(int i=0; i<4; ++i){
        if(i + pre_move == 3)//与上一步相反的移动
            continue;
        int nx = x + step[i][0];
        int ny = y + step[i][1];
        if(0<=nx && nx<SIZE && 0<=ny && ny<SIZE){
            solution[dv] = i;
            swap(board[x][y], board[nx][ny]);

            int new_bound = DFS(nx, ny, dv+1, i);
            if(ans)
                return new_bound;
            next_bound = min(next_bound, new_bound);

            swap(board[x][y], board[nx][ny]);
        }
    }
    return next_bound;
}

void IDA_star(int sx, int sy){
    ans = false;
    bound = h(board);//初始代价
    while(!ans && bound <= 100)//上限
        bound = DFS(sx, sy, 0, -10);
}

int main(){
    freopen("in", "r", stdin);

    int sx, sy;//起始位置
    char c;
    for(int i=0; i<SIZE; ++i)
        for(int j=0; j<SIZE; ++j){
            cin>>c;
            if(c == 'x'){
                board[i][j] = SIZE * SIZE;
                sx = i;
                sy = j;
            }
            else
                board[i][j] = c - '0';
        }

    IDA_star(sx, sy);

    if(ans){
        for(int i=0; i<bound; ++i)
            cout<<op[solution[i]];
    }
    else
        cout<<"unsolvable";

    return 0;
}

*/
#include<stdio.h>
#include<queue>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1000000;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重
//         0!1!2!3! 4! 5!  6!  7!   8!    9!
bool vis[MAXN];//标记

int cantor(int s[])//康拖展开求该序列的hash值
{
    int sum=0;
    for(int i=0;i<9;i++)
    {
        int num=0;
        for(int j=i+1;j<9;j++)
          if(s[j]<s[i])num++;
        sum+=(num*fac[9-i-1]);
    }
    return sum+1;
}
struct Node
{
    int s[9];
    int loc;//“0”的位置,把“x"当0
    int status;//康拖展开的hash值
    string path;//路径
};
string path;
int aim=46234;//123456780对应的康拖展开的hash值
int move[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//u,d,l,r
char indexs[5]="udlr";//正向搜索
Node ncur;
bool bfs()
{
    memset(vis,false,sizeof(vis));
    Node cur,next;
    queue<Node>q;
    q.push(ncur);
    while(!q.empty())
    {
        cur=q.front();
        q.pop();
        if(cur.status==aim)
        {
            path=cur.path;
            return true;
        }
        int x=cur.loc/3;
        int y=cur.loc%3;
        for(int i=0;i<4;i++)
        {
            int tx=x+move[i][0];
            int ty=y+move[i][1];
            if(tx<0||tx>2||ty<0||ty>2)continue;
            next=cur;
            next.loc=tx*3+ty;
            next.s[cur.loc]=next.s[next.loc];
            next.s[next.loc]=0;
            next.status=cantor(next.s);
            if(!vis[next.status])
            {
                vis[next.status]=true;
                next.path=next.path+indexs[i];

                if(next.status==aim)
                {
                    path=next.path;
                    return true;
                }

                q.push(next);
            }
        }
    }
    return false;
}
int main()
{
    char ch;
    while(cin>>ch)
    {
        if(ch=='x') {ncur.s[0]=0;ncur.loc=0;}
        else ncur.s[0]=ch-'0';
        for(int i=1;i<9;i++)
        {
            cin>>ch;
            if(ch=='x')
            {
                ncur.s[i]=0;
                ncur.loc=i;
            }
            else ncur.s[i]=ch-'0';
        }
        ncur.status=cantor(ncur.s);
        if(bfs())
        {
            cout<<path<<endl;
        }
        else cout<<"unsolvable"<<endl;
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值