• 【A*算法 + 康托展开 + 曼哈顿距离】hdu 1043 Eight(八数码问题)


    题目描述:

    http://acm.hdu.edu.cn/showproblem.php?pid=1043

     

    中文大意:

    经典八数码问题。

    给定初始状态,要求变换到目标状态并输出移动过程。

    目标状态固定为:1 2 3 4 5 6 7 8 x 。

     

    思路:

    采用A*算法 + 康托展开判重 + 曼哈顿距离做启发函数 的方法来做这道题。

    初始状态为广搜的起始状态,下一状态的选择依据为估价函数的大小。

    估价函数 = 初始状态到当前状态的代价 g + 当前状态到最终状态的代价 h

    其中,“当前状态到最终状态的代价”为估计值,有多种计算方式,这里采用“曼哈顿距离”来估计。

    两点间的曼哈顿距离:abs(x1 - x2) + abs(y1 - y2)

    估价值小的状态,应当优先被处理。

    故广搜过程中使用的队列为优先队列,优先级判断的依据为估价函数值(g + h)的大小。

    注意:①移动信息不能直接记录在 string 中,否则会超内存限制;

    ②杭电oj 上的这道题有多组数据,需要 while(cin>>temp)。

     

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    struct node{
        int state[9];//八数码状态 
        int pos;//'x'位置 
        int g,h;//g:bfs层数,即初始状态到现状态的代价
                //h:各点->目标位置的曼哈顿距离之和 
        
        //从小到大排序 
        bool operator<(const node& x)const{
            return (g + h) > (x.g + x.h);
        }
    };
    
    int start[9];
    int goal[9] = {1,2,3,4,5,6,7,8,0};
    
    //判断开始状态是否有解 
    //若逆序数为偶数,则有解
    //不统计'x' 
    bool have_result(){
        int sum = 0;
        for(int i=0;i<9;i++){
            if(!start[i]){
                continue;
            }
            
            for(int j=i+1;j<9;j++){
                if(start[j] && start[i] > start[j]){
                    sum++;
                }
            }
        }
        
        if(sum % 2 == 0){
            return true;
        }
        return false;
    }
    
    //移动信息 
    struct node2{
        int from;//前状态的 cantor 值 
        int dir;//前状态->现状态的移动方向 
    }paths[362880];
    
    //Cantor 计算会用到的常数 
    int factory[] = {1,1,2,6,24,120,720,5040,40320,362880};
    
    int Cantor(int state[], int n){
        int result = 0;
        for(int i=0;i<n;i++){
            int counted = 0;
            for(int j=i+1;j<n;j++){
                if(state[i] > state[j]){
                    counted++;
                }
            }
            result += counted * factory[n-i-1];
        }
        
        return result;
    }
     
    int gpos[9][2] = {{2,2},{0,0},{1,0},{2,0},{0,1},{1,1},{2,1},{0,2},{1,2}};
    
    //计算曼哈顿距离 
    int mht_dis(int state[]){
        int result = 0;
        for(int i=0;i<9;i++){
            if(state[i]){
                int x = i % 3;
                int y = i / 3;
                result += abs(x - gpos[state[i]][0]) + abs(y - gpos[state[i]][1]);
            }
        }
        
        return result;
    }
    
    char dir_str[4] = {'u','d','l','r'};
    
    void print(int cantor){
        char result[362880];
        int len = 0;
        //倒序遍历 
        while(paths[cantor].from != -1){
            result[len] = dir_str[paths[cantor].dir];
            len++;
            cantor = paths[cantor].from;
        }
        
        for(int i=len-1;i>=0;i--){
            printf("%c", result[i]);
        }
        printf("
    ");
    }
    
    bool visited[362880] = {false};
    int dir[4][2] = {{0,-1},{0,1},{-1,0},{1,0}};
    
    void a_star(){
        node head,next;
        memcpy(head.state, start, sizeof(start));
        for(int i=0;i<9;i++){
            if(head.state[i] == 0){
                head.pos = i;
                break;
            }
        }
        head.g = 0;
        head.h = mht_dis(head.state);
        
        int h_cantor = Cantor(head.state, 9);
        memset(visited, false, sizeof(visited));
        visited[h_cantor] = true;
        
        paths[h_cantor].from = -1;
            
        priority_queue<node> q;
        q.push(head);
        
        int g_cantor = Cantor(goal, 9);
        while(!q.empty()){
            head = q.top();
            q.pop();
            
            h_cantor = Cantor(head.state, 9);
                    
            if(h_cantor == g_cantor){
                print(g_cantor);
                return;
            }
            
            int px = head.pos % 3;
            int py = head.pos / 3;
            
            for(int i=0;i<4;i++){
                int nx = px + dir[i][0];
                int ny = py + dir[i][1];
                
                if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3){
                    memcpy(next.state, head.state, sizeof(head.state));
                    next.pos = ny * 3 + nx;
                    
                    swap(next.state[next.pos], next.state[head.pos]);
                    
                    int n_cantor = Cantor(next.state, 9);
                    if(!visited[n_cantor]){
                        visited[n_cantor] = true;
                        
                        next.g = head.g + 1;
                        next.h = mht_dis(next.state);
                        
                        paths[n_cantor].from = h_cantor;
                        paths[n_cantor].dir = i;
                        
                        q.push(next);
                    }
                }
            }
        }
    }
    
    int main(){
        char temp;
        while(cin>>temp){
            start[0] = temp - '0';
            if(start[0] > 9){
                start[0] = 0;
            }
            
            for(int i=1;i<9;i++){
                cin>>temp;
                
                start[i] = temp - '0';
                if(start[i] > 9){
                    start[i] = 0;
                }
            }
            
            if(!have_result()){
                cout << "unsolvable" << endl;
            }
            else{
                a_star();
            }
        }
    } 

     

    作者:老干妈就泡面
    本文版权归作者和博客园共有,欢迎转载,但请给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    qqzoneQQ空间漏洞扫描器的设计attilax总结
    Atitit.attilax重要案例 项目与解决方案与成果 v6 qa15
    Atitit atiuse软件系列
    Atitit 微信支付 支付结果通用通知
    Atitit 团队建设的知识管理
    Atitti  css   transition Animation differ区别
    Atitit 基于dom的游戏引擎
    Atitit 异常的实现原理 与用户业务异常
    Atitit dsl实现(1)------异常的库模式实现  异常的ast结构
    Atitit.uke 团队建设的组织与运营之道attilax总结
  • 原文地址:https://www.cnblogs.com/bjxqmy/p/14387149.html
Copyright © 2020-2023  润新知