【Luogu P1379】八数码难题
题目传送门
题意简介:
有一个3x3的方阵,编号为0的点表示空格子,每次可以将一个空格子与他上下左右的点进行交换,求达到目标状态的最小移动步数。
目标状态
1 2 3
8 0 4
7 6 5
分析
目测暴力bfs,7分,乱搞一下可以蹭到10分,剩余的是TLE&MLE
考虑如何优化:
由于我们发现每次移动之后方阵的状态可能与之前重复,所以可以考虑记搜判重;
但是如何判重?
康托展开、哈希……
在这里使用的是一个只有c++有的黑科技:map
map介绍:一个好用的东西,就是时间不太可观;可以将一个任何类型的东西当作下标来搞;所以可以考虑用来判重
我是很久以前写的代码了,所以写得可能有点丑:方阵中的每一个数都加上一个东西转换成一个字符并造出一个字符串,搞map判重,结束~~~~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<map>
using namespace std;
short b[5000000][4],a[5000000][4][4],x[4]={0,0,1,-1},y[4]={1,-1,0,0};
char s;
string cs=" ";
int bfs(){
map<string,int> gd;
register int head=0,foot=1,xx,yy,k;
b[1][3]=1;
do{
head++;
for(register int i=0;i<4;i++){
xx=b[head][1]+x[i];yy=b[head][2]+y[i];
if((xx>=1)&&(xx<=3)&&(yy>=1)&&(yy<=3)){
foot++;
b[foot][1]=xx;b[foot][2]=yy;b[foot][3]=b[head][3]+1;
for(register int j=1;j<=3;j++){
for(register int q=1;q<=3;q++){
a[foot][j][q]=a[head][j][q];
}
}
cs=" ";
swap(a[foot][b[head][1]][b[head][2]],a[foot][xx][yy]);
cs+=(char)a[foot][1][1]+'A';cs+=(char)a[foot][1][2]+'A';cs+=(char)a[foot][1][3]+'A';cs+=(char)a[foot][2][1]+'A';cs+=(char)a[foot][2][2]+'A';
cs+=(char)a[foot][2][3]+'A';cs+=(char)a[foot][3][1]+'A';cs+=(char)a[foot][3][2]+'A';cs+=(char)a[foot][3][3]+'A';
if(gd[cs]){foot--;continue;}
gd[cs]=1;
if(a[foot][1][1]==1&&a[foot][1][2]==2&&a[foot][1][3]==3&&a[foot][2][3]==4&&a[foot][3][3]==5&&a[foot][3][2]==6&&a[foot][3][1]==7&&a[foot][2][1]==8){return b[head][3];}
}
}
}while(head<foot);
return 0;
}
int main(){
for(register int i=1;i<=3;i++){
for(register int j=1;j<=3;j++){
cin>>s;
a[1][i][j]=s-'0';
if(a[1][i][j]==0){
b[1][1]=i;b[1][2]=j;
}
}
}
cout<<bfs();
}
/*拜屹大佬
屹大佬显灵AC!!
*/

浙公网安备 33010602011771号