zoukankan      html  css  js  c++  java
  • 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;
    }


    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    关于这个 blog
    P6499 [COCI2016-2017#2] Burza 题解
    CF1172F Nauuo and Bug 题解
    CF1479D Odd Mineral Resource 题解
    CF1442E Black, White and Grey Tree 题解
    CF1442D Sum 题解
    CF1025D Recovering BST 题解
    CF1056E Check Transcription 题解
    CF1025F Disjoint Triangles 题解
    红包算法的PHP实现
  • 原文地址:https://www.cnblogs.com/wanglaoda/p/4937128.html
Copyright © 2011-2022 走看看