题解 P2578 【九数码游戏】

P2578 [ZJOI2005]九数码游戏

题目大意

给定一个九宫格,通过两种操作变成目标状态,输出最少步数与变化过程。若无法变成目标状态,输出 "UNSOLVABLE" 。

solution:

考虑使用广搜优化( \(\text{BFS}+\text{Hash}\) )。
下面开始广搜。队列中我存了结构体类型,包括两个成员:

struct SI{
	string str; //当前状态
	int fl;//当前步数
}q[mo];//mo为哈希模数

我们用一个 \(\text{string}\) 类型来表示当前的状态,这样方便通过下标实现两种操作。
下面我们构建出广搜框架:

int h=1,t=0;
将初始状态入队;
while(h<=t){
	取出队头;
	如果当前状态与目标状态相同,返回当前步数;
	通过两种操作生成两个新状态;
  	判断新状态是否出现过,若没有{
		将该状态的字符串与当前步数+1做成结构题加入队尾;
		将该状态填入哈希表;
		记录路径;
   }
}

变换函数如下,直接模拟就好。

路径这里我们可以用一个 \(\text{map<long long,long long> lujing}\) 来记录。 \(\text{lujing[str]}\) 为此状态的前一步,通过 \(\text{while}\) 循环记录答案,最后倒序输出后再输出目标状态即可。省选题,开个 \(O2\) 也罢

接下来是细节的处理:

记录路径时需要将 \(\text{string}\) 类型转换成一个九位数:

long long zhuan(string str){
	long long s0,s1,s2,s3,s4,s5,s6,s7,s8;
	s0=(str[0]-'0')*100000000,s1=(str[1]-'0')*10000000,s2=(str[2]-'0')*1000000,
	s3=(str[3]-'0')*100000,   s4=(str[4]-'0')*10000,   s5=(str[5]-'0')*1000,
	s6=(str[6]-'0')*100,      s7=(str[7]-'0')*10,      s8=(str[8]-'0')*1;
	return s0+s1+s2+s3+s4+s5+s6+s7+s8;
}

输出这里需要将这个九位数拆开,一位一位输出:

//为了避免写崩,我一位一位拆开的[捂脸]
inline void print(long long lu){
	long long s0,s1,s2,s3,s4,s5,s6,s7,s8;
	s8=lu%10,lu/=10,s7=lu%10,lu/=10,s6=lu%10,lu/=10,
	s5=lu%10,lu/=10,s4=lu%10,lu/=10,s3=lu%10,lu/=10,
	s2=lu%10,lu/=10,s1=lu%10,lu/=10,s0=lu%10,lu/=10,
	printf("%lld %lld %lld\n",s0,s1,s2);
	printf("%lld %lld %lld\n",s3,s4,s5);
	printf("%lld %lld %lld\n\n",s6,s7,s8);//此处两个换行!
}

看到这的同学,可以自己去写代码了(tf口吻)

代码
#include<cstdio>
#include<map>
#include<cstring>
#include<iostream>
#define mo 362885 
using namespace std;
string astr="012345678";
string smo[mo];
int hd[mo+2],nt[mo+2],cnt;
long long sans[mo];
map<long long,long long> lujing;
struct SI{
	string str;
	int fl;
}q[mo];
inline int sh(string str){
	return (str[0]*31+str[1]*991+str[2]*143+str[3]*691+str[4]*779+str[5]*1193+str[6]*2911/str[7]/87+str[8]%553)%mo;
}
inline void tian(string str){
	int lei=sh(str);
	smo[++cnt]=str,nt[cnt]=hd[lei],hd[lei]=cnt;
}
inline bool zhao(string str)
{
	int lei=sh(str);
	for(int i=hd[lei];i!=-1;i=nt[i]){
		if(smo[i]==str) 
			return true;
	}
	return false;
}
string bian1(string str){
	string skr;
	string s0,s1,s2,s3,s4,s5,s6,s7,s8;
	s0=str[3],s1=str[0],s2=str[1],
	s3=str[6],s4=str[4],s5=str[2],
	s6=str[7],s7=str[8],s8=str[5];
	skr=s0+s1+s2+s3+s4+s5+s6+s7+s8;
	return skr;
}
string bian2(string str){
	string skr;
	string s0,s1,s2,s3,s4,s5,s6,s7,s8;
	s0=str[0],s1=str[1],s2=str[2],
	s3=str[5],s4=str[3],s5=str[4],
	s6=str[6],s7=str[7],s8=str[8];
	skr=s0+s1+s2+s3+s4+s5+s6+s7+s8;
	return skr;
}
long long zhuan(string str){
	long long s0,s1,s2,s3,s4,s5,s6,s7,s8;
	s0=(str[0]-'0')*100000000,s1=(str[1]-'0')*10000000,s2=(str[2]-'0')*1000000,
	s3=(str[3]-'0')*100000,   s4=(str[4]-'0')*10000,   s5=(str[5]-'0')*1000,
	s6=(str[6]-'0')*100,      s7=(str[7]-'0')*10,      s8=(str[8]-'0')*1;
	return s0+s1+s2+s3+s4+s5+s6+s7+s8;
}
inline int bfs(string kai){
	int h=1,t=0;
	SI now; now.str=kai,now.fl=0;
	q[++t]=now;
	while(h<=t){
		now=q[h++];
		if(now.str==astr) return now.fl;
		int zuifl=now.fl;
		string str=now.str;
		string b1=bian1(str);
		if(!zhao(b1)){
			now.fl=zuifl+1,now.str=b1;
			q[++t]=now;
			tian(b1);
			lujing[zhuan(b1)]=zhuan(str);
			//printf("lujing[%d]=%d\n",zhuan(b1),zhuan(str));
		}
		string b2=bian2(str);
		if(!zhao(b2)){
			now.fl=zuifl+1,now.str=b2;
			q[++t]=now;
			tian(b2);
			lujing[zhuan(b2)]=zhuan(str);
			//printf("lujing[%d]=%d\n",zhuan(b2),zhuan(str));
		}
	}
}
inline void print(long long lu){
	long long s0,s1,s2,s3,s4,s5,s6,s7,s8;
	s8=lu%10,lu/=10,s7=lu%10,lu/=10,s6=lu%10,lu/=10,
	s5=lu%10,lu/=10,s4=lu%10,lu/=10,s3=lu%10,lu/=10,
	s2=lu%10,lu/=10,s1=lu%10,lu/=10,s0=lu%10,lu/=10,
	printf("%lld %lld %lld\n",s0,s1,s2);
	printf("%lld %lld %lld\n",s3,s4,s5);
	printf("%lld %lld %lld\n\n",s6,s7,s8);
}
int main(){
	memset(hd,-1,sizeof(hd));
	string kai;
	for(int i=0;i<9;i++){
		string a; cin>>a;
		kai+=a;
	}
	int ans=bfs(kai);
	lujing[zhuan(kai)]=0;
	if(!ans) {
		printf("UNSOLVABLE\n");
		return 0;
	}
	printf("%d\n",ans);
	string str=astr;
	long long lu=zhuan(str);
	int cnt=0;
	while(lujing[lu]){
		//printf("%lld\n",lu);
		lu=lujing[lu];
		sans[++cnt]=lu;
	}
	for(int i=cnt;i>=1;i--)
		print(sans[i]);
	print(zhuan(str));
	return 0;
}

End

posted @ 2021-07-29 19:40  Mr_think  阅读(99)  评论(0)    收藏  举报