历届试题 九宫重排
时间限制:1.0s 内存限制:256.0MB
问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758样例输出
3
样例输入
13524678.
46758123.样例输出
22
bfs 总共9!(360000+)种状态,bool开vis本机可以运行,但是超内存了。。
改用set记录是否出现该状态,增加log复杂度。
总复杂度O(nlogn)
康托判重(排列性质)可以把复杂度将为O(n)。
#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define LL long long
#define pai acos(-1)
#define MAXN 100
struct no{
LL now;
int step;
}node,node2;
set<int> s;
int go[4][2]={0,1,1,0,-1,0,0,-1};
int t[3][3];
LL Hash(char *p){
LL x=0;int le=strlen(p);
for(int i=0;i<le;i++) {
if(p[i]=='.') x=x*10+9;
else
x=x*10+p[i]-'0';
}
return x;
}
bool check(int h,int l){
if(h<0||l<0||h>2||l>2) return 0;
return 1;
}
int main(){
char st[15],en[15];
cin>>st>>en;
LL INTen=Hash(en);
queue<no> q;
LL x=Hash(st);
node.now=x;node.step=0;
s.insert(x);
q.push(node);
while(!q.empty()){
int th,tl,h,l;
node=q.front();
x=node.now;
if(x==INTen){
cout<< node.step;
return 0;
}
h=2;l=2;
for(int i=8;i>=0;i--){
t[h][l]=x%10;
l--;
if(l==-1){
h--;
l=2;
}
x=x/10;
}
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
if(t[i][j]==9){
h=i;
l=j;
}
for(int i=0;i<4;i++){
th=go[i][0]+h;
tl=go[i][1]+l;
if(check(th,tl)==0) continue;
int tt=t[th][tl];
t[th][tl]=t[h][l];
t[h][l]=tt;
int xx=0,yy=0;
x=0;
for(int i=0;i<=8;i++){
x=x*10+(LL)t[xx][yy];
yy++;
if(yy==3){
yy=0;
xx++;
}
}
if(s.find(x)==s.end()){
node2.now=x;node2.step=node.step+1;
q.push(node2);
s.insert(x);
}
tt=t[th][tl];
t[th][tl]=t[h][l];
t[h][l]=tt;
}
q.pop();
}
if(q.empty()){
cout<<-1;
}
return 0;
}