题解 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;
}

浙公网安备 33010602011771号