蓝桥杯 九宫重排(bfs)(cf2)

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

我们把第一个图的局面记为:12345678.

把第二个图的局面记为:123.46758

显然是按从上到下,从左到右的顺序记录数字,空格记为句点。

本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出 −1。

Input

输入第一行包含九宫的初态,第二行包含九宫的终态。

Output

输出最少的步数,如果不存在方案,则输出 −1。

input

12345678.
123.46758

output

3

思路:

1、找最少步数,最佳方案,最短路,显然是用广搜更合适。

2、此题的关键之处就在于如何剪枝。走过的状态需要标记,不然重复去走已经走过的路就会超内存。每一个状态都可以用唯一的一个九位数字来表示,“.”用数字9来表示,把走过的状态存入一个set。每次走到一个位置都判断一下,set中是否已经存在此位置。

3、直接用string来存储比用二维邻接矩阵要简单得多,注意在判断下一步是否可走时,还是需要二维数组来判断,这时需要字符串与二维数组的转换,通过找规律进行正确且简洁的转换。

详情见ac代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
int nextx[4]={-1,0,1,0};
int nexty[4]={0,1,0,-1};
struct node
{
    int x,cnt;
    string s;
};
long long f(string s)
{
    int i;
    long long num=0,base=1;
    for(i=0;i<=8;i++)
    {
        if(s[i]=='.')
            num+=9*base;
        else
            num+=(s[i]-'0')*base;
        base*=10;
    }
    return num;
}
int main()
{
    set<long long> a;
    queue<node> q;
    node n,m;
    int i,mi,mj,nx,ny,ans=-1;
    string s1,s2;
    cin>>s1>>s2;
    for(i=0;i<=8;i++)
        if(s1[i]=='.')
            mi=i;
    n.x=mi,n.cnt=0,n.s=s1;
    q.push(n);
    while(!q.empty())
    {
        n=q.front();
        q.pop();
        if(n.s==s2)
        {
            ans=n.cnt;
            break;
        }
        a.insert(f(n.s));
        mi=n.x/3,mj=n.x%3;
        for(i=0;i<4;i++)
        {
            nx=mi+nextx[i];
            ny=mj+nexty[i];
            if(nx>=0&&nx<=2&&ny>=0&&ny<=2)
            {
                m.x=nx*3+ny,m.cnt=n.cnt+1,m.s=n.s;
                swap(m.s[n.x],m.s[m.x]);
                if(a.count(f(m.s))==0)
                    q.push(m);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}
发布了7 篇原创文章 · 获赞 0 · 访问量 175

猜你喜欢

转载自blog.csdn.net/weixin_43790882/article/details/104019877
今日推荐