九宫重排 蓝桥杯c++ 题解 字符串hash+bfs

九宫重排 蓝桥杯c++ 题解 字符串hash+bfs

题意:给出一个九宫格,你可以将与空格相邻的数字和空格进行交换,目的是得到另一个九宫格,问最少的步数。

思路:从最小步数不难看出我们可以使用广度优先搜索去计算最小步数,但是如何记录九宫格的状态是一个难题。我使用的方法是将九宫格看成一个长度为9的字符串,然后通过字符串hash去记录它的状态。

以下是我的字符串hash代码

#define ll long long
ll hashh(string str){
    ll k=0,t;
    for(int i=0;i<9;i++){
	  if(str[i]=='.')t=11;
	  else t=str[i]-'0';
	  k=k*13+t;
    }
    return k;
}

hash之后得到的值可以直接用map容器进行标记,这样就可以避免搜索过的状态再重复搜索。然后我们下次bfs的时候只需要将字符串中的空格位置找出来,然后对空格的相邻的四个位置进行判断,如果合法(位置在九宫格中)且交换后的状态之前没有出现过则可以存入队列中。

通过字符串得到空格位置的代码:

  for(int i=0;i<9;i++){
    if(str[i]=='.'){
        x=i/3+1;
        y=i%3+1;
        break;
    }
}

但为了查找空格位置的四个方向更加方便,我们可以直接在用字符串得到九宫图的过程中,得到空格位置。代码如下:

            int idx=0,q[4][4];
			for(int i=1;i<=3;i++){
				for(int j=1;j<=3;j++){
					if(str[idx]=='.'){
						qq[i][j]=11;//赋值为11,是因为我字符串hash的时候空格的值给的是11。
						x=i,y=j;
					}
					else qq[i][j]=str[idx]-'0';
					idx++;
				}
			}

既然得到了空格位置,我们接下来就只需要枚举四个方向进行搜索,并重复此步骤就可得到答案。

解题代码:

#include<bits/stdc++.h>
using namespace std;
string str,str1;
#define ll long long
struct tt{
	string str;
	ll step;
	ll f;
};
ll f=0;
map<ll,int>mp;
int aa[4][2]={-1,0,0,-1,0,1,1,0};
ll hashh(string str){
    ll k=0,t;
    for(int i=0;i<9;i++){
	  if(str[i]=='.')t=11;
	  else t=str[i]-'0';
	  k=k*13+t;
    }
    return k;
}
int bfs(string str,ll w){
	tt ff;
	ff.f=w,ff.step=0,ff.str=str;
	queue<tt>q;
	q.push(ff);
	while(!q.empty()){
		tt node=q.front();
		q.pop();
		if(node.f==f){//和末尾状态相同,输出答案
			printf("%d\n",node.step);
			return 0;
		}
		else {
			int qq[10][10],x,y;
			int idx=0;
			for(int i=1;i<=3;i++){//字符串得到九宫格
				for(int j=1;j<=3;j++){
					if(node.str[idx]=='.'){
						qq[i][j]=11;
						x=i,y=j;
					}
					else qq[i][j]=node.str[idx]-'0';
					idx++;
				}
			}
			for(int i=0;i<4;i++){//枚举相邻四个位置
				int xx=x+aa[i][0];
				int yy=y+aa[i][1];
				if(xx>=1&&yy>=1&&xx<=3&&yy<=3){//判断位置是否合法
					int pp[10][10];
					int t=qq[xx][yy],ttt=qq[x][y];//记录将要交换位置的值
					ll wwe=0;
					string str="";
					for(int i=1;i<=3;i++){//得到交换后的字符串
						for(int j=1;j<=3;j++){
							if(i==xx&&j==yy){
								pp[i][j]=ttt;
								str+='.';
							}
							else if(i==x&&j==y){
								pp[i][j]=t;
								str+=pp[i][j]+'0';
							}
							else {
								pp[i][j]=qq[i][j];
								str+=pp[i][j]+'0';
							}
						}
					}
                    wwe=hashh(str);
					if(mp[wwe])continue;//此状态已经出现过直接continue
					else{
						mp[wwe]=1;//标记状态
						ff.f=wwe,ff.step=node.step+1,ff.str=str;
						q.push(ff);
					}
				}
			}
		}
	}
}
int main(){
	cin>>str;
	cin>>str1;
	ll k=hashh(str);
	mp[k]=1;
	f=hashh(str1);
	bfs(str,k);
}

第一次写博客,没写好请见谅(逃)

上一篇:用html自己开发自己的串口TCP通讯调试软件


下一篇:av_parser_parse2用法以及解读