题意:
7数码问题。在2×4的棋盘上,摆有7个棋子,每个棋子上标有1至7的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格(用0表示),与空格相邻(上下左右)的棋子可以移到空格中,该棋子原先位置成为空格。
给出一个初始状态(保证可以转移到最终状态),最终状态为0 1 2 3 4 5 6 7,找出一种从初始状态转变成最终状态的移动棋子步数最少的移动步骤。
输入:
多组输入,每组8个数,表示初始状态前四个数为第一行从左到右,后四个数为第二行从左到右。
输出:
至少需要多少步可以从输入状态到达最终状态
Sample Input
0 1 2 3 4 5 6 7
1 0 2 3 4 5 6 7
7 6 5 4 3 2 1 0
Output for the Sample Input
0
1
28
答案:
#include <stdio.h> #include <string.h> #include <queue> #define MAX_N 100 using namespace std; char g[MAX_N][9] = {0}; //目标状态 int dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1}; //0的移动方向 int dp[8][8][8][8][8][8][8][8]; //保存达到各个状态的最小移动次数 int n; //输入的最终状态个数 //各个状态的信息 typedef struct { char d[9]; //状态 int n; //移动的次数 int idx; //0的位置 }Data; //保存已经达到的状态的最小移动次数 void SetFlag(char d[], int n) { dp[d[0]-'0'][d[1]-'0'][d[2]-'0'][d[3]-'0'][d[4]-'0'][d[5]-'0'][d[6]-'0'][d[7]-'0'] = n; } //获取某个状态的最小移动次数 int GetFlag(char d[]) { return dp[d[0]-'0'][d[1]-'0'][d[2]-'0'][d[3]-'0'][d[4]-'0'][d[5]-'0'][d[6]-'0'][d[7]-'0']; } //bfs遍历所有可能达到的状态 void bfs() { queue<Data> que; Data dt = {"01234567", 0, 0}; que.push(dt); SetFlag(dt.d, 0); while(que.size()){ dt = que.front(); que.pop(); int x = dt.idx / 4, y = dt.idx % 4; for(int i = 0; i < 4; i ++){ int nx = x + dx[i], ny = y + dy[i]; if(nx >= 0 && nx < 2 && ny >= 0 && ny < 4){ Data ndt = dt; ndt.idx = nx * 4 + ny; ndt.d[dt.idx] = ndt.d[ndt.idx]; ndt.d[ndt.idx] = '0'; if(-1 == GetFlag(ndt.d)){ SetFlag(ndt.d, ++ ndt.n); que.push(ndt); } } } } } void solve() { memset(dp, -1, sizeof(dp)); bfs(); for(int i = 0; i < n; i ++) printf("%d\n", GetFlag(g[i])); } int main() { scanf("%d", &n); for(int ch, i = 0; i < n; i ++) for(int j = 0; j < 8; j ++){ scanf("%d", &ch); g[i][j] = ch + '0'; } solve(); return 0; }
思路:
可以把01234567看做是起始状态,把输入的看做是最终要达到的状态,因此以01234567为起始状态用bfs搜索所有可能达到的状态,并保存这些状态,然后输出即可;而每次都用bfs则可能会TLE(超时)