【蓝桥杯】历届试题 九宫重排

问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。

  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出

22

 

【解题思路】

抽象为图模型,空格开始上下左右四个方向搜索,因为求最短路径,用bfs

 

九个格子的各种变换一共有 9! 种, 用康托展开将各种状态映射为一个数字

然后用一个数组 status[400000]记录各种状态是否到达过

 

【代码】

 1 #include<iostream>
 2 #include<queue>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //x, y 上 -1 0 下 1 0  左 0 -1 右 0 1 
 7 int fa[10] = { 1, 1, 2, 6, 24 };
 8 int status[400000];    //记录每种状态 
 9 
10 struct Node{
11     int x, y;        // 记录 . 的坐标 
12     char s[12];        //记录状态 
13     int status;
14     int pos;        //记录 . 在s[12]中的下标 
15     int step;        //到这个状态最少所用的步数 
16 };
17 
18 //获得1! ~ 9! 
19 void getfa(){
20     for(int i = 5; i<=9; ++i){
21         fa[i] = fa[i-1] * i;
22     }
23 }
24 
25 //康托展开 
26 int cantor(char * s){
27     int ans  = 0;
28     for(int i=0;i<9;++i){
29         int num = 0;
30         for(int j=i+1;j<9;++j){
31             if(s[j]<s[i]) num++;
32         }
33         ans = ans + num*fa[8-i];
34     }
35     return ans;
36 }
37 
38 
39 void bfs(){
40     Node beginnode;
41     char end[12], temps[12];            //初始位置
42     scanf("%s%s", beginnode.s, end);    
43     beginnode.status = cantor(beginnode.s);
44     for(int i=0;i<3;++i){
45         for(int j=0;j<3;++j){
46             if(beginnode.s[i*3+j] == '.'){
47                 beginnode.x = i;
48                 beginnode.y = j;
49                 beginnode.pos = i*3+j;
50             }
51         }
52     }
53     beginnode.step = 0;
54     int endc = cantor(end);
55     
56     queue<Node> q;
57     q.push(beginnode);
58     status[beginnode.status] = 1;
59     
60     while(!q.empty()){
61         Node cur = q.front();
62         q.pop();
63         if(endc == cur.status){
64             printf("%d", cur.step);
65             return;
66         }
67             
68         Node addnode;
69         for(int i=0;i<4;++i){
70             int nx = cur.x + dir[i][0];
71             int ny = cur.y + dir[i][1]; 
72             int np = nx * 3 + ny; 
73             if(nx>=0 && nx<=2 && ny>=0 && ny<=2){
74                 for(int j=0;j<9;++j){
75                     addnode.s[j] = cur.s[j];
76                 }
77                 addnode.s[cur.pos] = cur.s[np];
78                 addnode.s[np] = cur.s[cur.pos];
79                 addnode.status = cantor(addnode.s);
80                 if(status[addnode.status] == 0){
81                     addnode.x = nx;
82                     addnode.y = ny;
83                     addnode.pos = np;
84                     addnode.step = cur.step+1;
85                     status[addnode.status] = 1;
86                     q.push(addnode);
87                 } 
88             } 
89         }        
90     }
91     printf("-1");
92 }
93 
94 int main(){
95     memset(status, 0, sizeof(status));
96     getfa();
97     bfs();
98     return 0;
99 }
AC

 

 

最开始,判断位置出现了错误。。。。

将二维坐标转化为一维,然后四个方向分别+1,-1,+3,-3 

苦思不得其解,就测试写了个打印路径的,一看就清楚了

#include<iostream>
#include<queue>
#include<cstring>
#include<vector>
using namespace std;

int dir[4] = {-3, 3, -1, 1}; //x, y 上 -3 下 +3  左 -1 右 +1 
int fa[10] = { 1, 1, 2, 6, 24 };
int status[400000];    //记录每种状态 

//test
int testid = -1;
char test[400000][12];


struct Node{
    char s[12];
    int status;
    int pos;
    int step;
    
    vector<int> ids;
};



void getfa(){
    for(int i = 5; i<=9; ++i){
        fa[i] = fa[i-1] * i;
    }
}

int cantor(char * s){
    int ans  = 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++;
        }
//        cout << " num  " << num << endl;
        ans = ans + num*fa[8-i];
    }
    return ans;
}

void bfs(){
    Node beginnode;
    char end[12], temps[12];            //初始位置
    scanf("%s%s", beginnode.s, end);    
    beginnode.status = cantor(beginnode.s);
    for(int i=0;i<9;++i){
        if(beginnode.s[i]=='.'){
            beginnode.pos = i;
            break;
        }
    }
    beginnode.step = 0;
    int endc = cantor(end);
    
    queue<Node> q;
    
    
    beginnode.ids.push_back(++testid);
    for(int k=0;k<9;++k){
        test[testid][k] = beginnode.s[k];
    }
    
    
    q.push(beginnode);
    status[beginnode.status] = 1;
    
    while(!q.empty()){
        Node cur = q.front();
        
//        for(int i=0;i<9;++i) cout << cur.s[i]; 
//        cout << "    " << cur.status << endl;
        
        
//        for(int i=0;i<9;++i){
//            if(i%3==0){
//                cout << endl;
//            }
//            cout << cur.s[i];
//        }
//        cout << endl;
//        getchar();
        
        
        q.pop();
        if(endc == cur.status){
            for(int kk=0;kk<cur.ids.size();++kk){
                for(int jj=0;jj<9;++jj){
                    if(jj%3==0){
                        cout << endl;
                    }
                    cout << test[cur.ids[kk]][jj];
                }
                cout << endl;
            }
            return;
        }
        
        
        Node addnode;
        for(int i=0;i<4;++i){
            int np = cur.pos + dir[i];
            if(np>=0 && np<=8){
                for(int j=0;j<9;++j){
                    addnode.s[j] = cur.s[j];
                }
                addnode.s[cur.pos] = cur.s[np];
                addnode.s[np] = cur.s[cur.pos];
                addnode.status = cantor(addnode.s);
                
                if(status[addnode.status] == 0){
                    addnode.pos = np;
                    addnode.step = cur.step+1;
                    status[addnode.status] = 1;
                    
                    /////
                    addnode.ids.assign(cur.ids.begin(), cur.ids.end());
                    addnode.ids.push_back(++testid);
                    for(int k=0;k<9;++k){
                        test[testid][k] = addnode.s[k];
                    }
                                    
                    
                    
                    q.push(addnode);
                } 
            } 
        }        
    }
    printf("-1");
}

int main(){
    memset(status, 0, sizeof(status));
    getfa();
    bfs();
    return 0;
}
错误测试代码

 

转载于:https://www.cnblogs.com/chsobin/p/8624705.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值