历届试题 九宫重排 蓝桥杯

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

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

22


广搜

队列,hash验重

#include<cstdio>
#include<cstring>
const int state_maxsize=400010;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
typedef int state[9];
state q[state_maxsize],goal;
int dist[state_maxsize]={0};
const int hash_size=10000000;
int head[hash_size]={0},next[state_maxsize];
int hash(state &x){
int sum=0;
for(int i=0;i<9;i++)
    sum=sum*10+x[i];
return sum%hash_size;
}
int try_to_sert(int x){
int h=hash(q[x]);
int u=head[h];
while(u){
    while(memcmp(q[u],q[x],sizeof(q[x]))==0){
            return 0;
    }
    u=next[u];
}
next[x]=u;
head[h]=x;
return 1;
}
int bfs(){
int front=1;
int rear=2;
while(front<rear){
    state&s=q[front];
    if(memcmp(goal,s,sizeof(s))==0)return front;
    int z=0;
    while(s[z]!=0)z++;
    int x=z/3;
    int y=z%3;
    for(int i=0;i<4;i++){
        int newx=x+dx[i];
        int newy=y+dy[i];
        int newz=newx*3+newy;
        if(newx>=0&&newx<3&&newy>=0&&newy<3){
            state&t=q[rear];
            memcpy(t,s,sizeof(s));
            t[newz]=s[z];
            t[z]=s[newz];
            dist[rear]=dist[front]+1;
            if(try_to_sert(rear))rear++;

        }
    }
    front++;
}
return 0;
}
int main(){
char c;
for(int i=0;i<9;i++){
    if((c=getchar())!='.')
        q[1][i]=c-'0';
    else
        q[1][i]=0;
}
getchar();
for(int i=0;i<9;i++){
    if((c=getchar())!='.')
        goal[i]=c-'0';
    else
        goal[i]=0;
}
if(int y=bfs())
        printf("%d\n",dist[y]);
else
        printf("-1\n");
}


双向搜索

与单向广搜的区别,在于把起点终点依次放入队列,然后你一层,我一层地遍历;验重的时候,分辨是于哪个出发点出发的路径重叠。

#include<cstdio>
#include<cstring>
const int state_maxsize=400010;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
typedef int state[9];
state q[state_maxsize];
int dist[state_maxsize]={0};
int root[state_maxsize]={0};
const int hash_size=10000000;
int head[hash_size]={0},next[state_maxsize];
int hash(state &x){
int sum=0;
for(int i=0;i<9;i++)
    sum=sum*10+x[i];
return sum%hash_size;
}
int try_to_sert(int x){
int h=hash(q[x]);
int u=head[h];
while(u){
    while(memcmp(q[u],q[x],sizeof(q[x]))==0){
            if(root[u]==root[x])
                return 0;
            else
                return u;
    }
    u=next[u];
}
next[x]=u;
head[h]=x;
return 1;
}
int bfs(){
root[1]=1;
root[2]=2;
int front=1;
int rear=3;
while(front<rear){
    state&s=q[front];
    int z=0;
    while(s[z]!=0)z++;
    int x=z/3;
    int y=z%3;
    for(int i=0;i<4;i++){
        int newx=x+dx[i];
        int newy=y+dy[i];
        int newz=newx*3+newy;
        if(newx>=0&&newx<3&&newy>=0&&newy<3){
            state&t=q[rear];
            memcpy(t,s,sizeof(s));
            t[newz]=s[z];
            t[z]=s[newz];
            root[rear]=root[front];
            dist[rear]=dist[front]+1;
            switch(int u=try_to_sert(rear)){
            case 0:break;
            case 1:rear++;break;
            default:return dist[u]+dist[rear];
            }
        }
    }
    front++;
}
return 0;
}
int main(){
char c;
for(int i=0;i<9;i++){
    if((c=getchar())!='.')
        q[1][i]=c-'0';
    else
        q[1][i]=0;
}
getchar();
for(int i=0;i<9;i++){
    if((c=getchar())!='.')
        q[2][i]=c-'0';
    else
        q[2][i]=0;
}
if(int y=bfs())
        printf("%d\n",y);
else
        printf("-1\n");
}


蓝桥oj上单向花了156ms,双向花了15ms。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值