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;
    }


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

  • 相关阅读:
    图的概念、存储、遍历、最短路径问题、最小生成树、拓扑排序、关键路径
    Nginx负载均衡
    Nginx反向代理
    Nginx配置虚拟主机
    Linux下Nginx安装
    freemarker使用
    ActiveMQ与spring整合
    ActiveMQ安装
    全局异常处理
    solr整合spring
  • 原文地址:https://www.cnblogs.com/wanglaoda/p/4937128.html
Copyright © 2011-2022 走看看