蓝桥杯 历届试题 九宫重排 (八数码问题--康托展开去重 + bfs搜索)

时间:2022-11-23 09:49:56

题意:

简单的八数码问题:

给你两个状态 求最少步数。

可以把点变成9:

这样,9个数都不一样,相当于是阶乘的排列。

直接用bfs 搜索 康托展开去重即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <queue>

#define Siz(x) (int)x.size()
#define get(x) (3.1415926*4*x*x*x/3.0)
using namespace std;
typedef long long LL;

const double pi = 3.1415926;
const double eps = 1e-12;

const int dx[] = {1,-1,0,0};
const int dy[] = {0,0,-1,1};


bool vis[400000];
int JIE[10];


void init(){
JIE[0] = 1;
for (int i = 1; i <= 9; ++i) JIE[i] = JIE[i-1] * i;


// printf("%d\n", JIE[9]);
}
char hs[10];



int HASH(int x){
int tx = x;
for (int i = 0; i < 9; ++i){
hs[8-i] = tx % 10;
tx /= 10;
}
int sum = 0;
for (int i = 0; i < 9; ++i){
int t = 0;
for (int j = i + 1; j < 9; ++j){
if (hs[j] < hs[i])++t;
}
sum += JIE[8-i] * t;
}
return sum;
}

char st[10], ed[10];

queue<int>q;
int dp[400000];
char s[10];
int a[5][5];
int bfs(int sv,int ev){

int hashsv = HASH(sv);
q.push(sv);
vis[hashsv] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
if (u == ev) return dp[HASH(ev)];
int tu = u;
for (int i = 0; i < 9; ++i) {
s[8-i] = tu % 10 + 48;
tu /= 10;
}
int x,y;
for (int i = 0; i < 9; ++i){
a[i/3 ][i%3 ] = s[i] - 48;

if (s[i] == '9'){
x = i/3;
y = i % 3;
}
}

for (int i = 0; i < 4; ++i){
int xx = dx[i] + x;
int yy = dy[i] + y;
if (xx < 0 || yy < 0 || xx >2 || yy > 2) continue;

swap(a[xx][yy],a[x][y] );
int nxt = 0;
for (int j = 0; j < 3; ++j){
for (int k = 0; k < 3; ++k){
nxt = nxt * 10 + a[j][k];
}
}
swap(a[xx][yy], a[x][y]);
int hashnxt = HASH(nxt);
if (!vis[hashnxt]){
vis[hashnxt] = 1;
q.push(nxt);
dp[hashnxt] = dp[HASH(u)] + 1;
}
}
}

return -1;
}


int main(){
init();


scanf("%s%s",st,ed);
for (int i = 0; i < 9; ++i){
if (st[i] == '.') st[i] = '9';
if (ed[i] == '.') ed[i] = '9';
}

int sv = 0, ev = 0;
for (int i = 0; i < 9; ++i){
sv = sv * 10 + st[i] - 48;
ev = ev * 10 + ed[i] - 48;
}
int ans = bfs(sv,ev);
printf("%d\n",ans);
return 0;
}





  历届试题 九宫重排  时间限制:1.0s   内存限制:256.0MB      问题描述  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
蓝桥杯 历届试题 九宫重排  (八数码问题--康托展开去重 + bfs搜索)蓝桥杯 历届试题 九宫重排  (八数码问题--康托展开去重 + bfs搜索)
  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式  输入第一行包含九宫的初态,第二行包含九宫的终态。输出格式  输出最少的步数,如果不存在方案,则输出-1。样例输入12345678.
123.46758
样例输出3样例输入13524678.
46758123.
样例输出22
 

  历届试题 九宫重排  时间限制:1.0s   内存限制:256.0MB      问题描述  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
蓝桥杯 历届试题 九宫重排  (八数码问题--康托展开去重 + bfs搜索)蓝桥杯 历届试题 九宫重排  (八数码问题--康托展开去重 + bfs搜索)
  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式  输入第一行包含九宫的初态,第二行包含九宫的终态。输出格式  输出最少的步数,如果不存在方案,则输出-1。样例输入12345678.
123.46758
样例输出3样例输入13524678.
46758123.
样例输出22