1151. 魔板
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge
Description
题目和A题相同,在这里我们把数据范围扩大:N可能超过10。
请仔细考虑各种情况。Input
输入包括多个要求解的魔板,每个魔板用三行描述。
第一行步数N,表示最多容许的步数。
第二、第三行表示目标状态,按照魔板的形状,颜色用1到8的表示。
当N等于-1的时候,表示输入结束。Output
对于每一个要求解的魔板,输出一行。
首先是一个整数M,表示你找到解答所需要的步数。接着若干个空格之后,从第一步开始按顺序给出M步操作(每一步是A、B或C),相邻两个操作之间没有任何空格。
注意:如果不能达到,则M输出-1即可。Sample Input
45 8 7 64 1 2 338 7 6 51 2 3 4-1
Sample Output
2 AB1 A评分:M超过N或者给出的操作不正确均不能得分。
Problem Source
ZSUACM Team Member
#include<iostream>
#include<queue>
#include<string>
#include<memory h="">
using namespace std;
//利用康托展开,请先自行百度简单了解一下。
// 记录0-7的阶乘
int fac[8] = { 1, 1, 2, 6, 24, 120, 720, 5040 };
// 构造一个visit数组,来记录新节点是否在之前已经访问过。 总共有8!=40320种情况
bool visit[40321];
struct node {
// 魔板上行
int x;
// 魔板下行
int y;
// 已经进行的操作次数
int count;
// 操作序列
string step;
node() {
x = y = count = 0;
step = "";
}
node(int x1, int y1, int a, string b) :x(x1), y(y1), count(a), step(b) {}
};
int init() {
int a = 0, b;
for (int i = 0; i < 4; i++) {
cin >> b;
a = a * 10 + b;
}
return a;
}
// 获取新得到的节点的康托编码。(也即这个状态对应的数组下标)
int getcode(node top) {
int i = 7, k = 3;
int n = 0;
int a[8];
for (int j = 3; j >= 0; j--) {
a[i--] = top.y % 10;
a[k--] = top.x % 10;
top.y /= 10;
top.x /= 10;
}
// 当前 未出现 的元素中是排在第几个
for (int i = 0; i < 8; i++) {
int count = 0;
for (int j = i + 1; j < 8; j++) {
if (a[i] > a[j]) {
count++;
}
}
n += count * fac[7 - i];
}
return n;
}
void way(node top, int i, queue<node>& q) {
node newnode;
newnode.count = top.count + 1;
if (i == 0) {
newnode.x = top.y;
newnode.y = top.x;
newnode.step = top.step + "A";
}
else if (i == 1) {
newnode.x = top.x % 10 * 1000 + top.x / 10;
newnode.y = top.y % 10 * 1000 + top.y / 10;
newnode.step = top.step + "B";
}
else {
int hx = top.x / 100 % 10;
int tx = top.x / 10 % 10;
int hy = top.y / 100 % 10;
int ty = top.y / 10 % 10;
newnode.x = top.x / 1000 * 1000 + hy * 100 + hx * 10 + top.x % 10;
newnode.y = top.y / 1000 * 1000 + ty * 100 + tx * 10 + top.y % 10;
newnode.step = top.step + "C";
}
//判断新节点是否已经被访问过。没访问过,加入队列。
if (visit[getcode(newnode)] == false) {
visit[getcode(newnode)] = true;
q.push(newnode);
}
}
int main() {
int maxstep;
int x1 = 1234;
int y1 = 8765;
cin >> maxstep;
while (maxstep != -1) {
int flag = 1;
int endx = init();
int endy = init();
memset(visit, false, sizeof(visit));
visit[0] = true;
queue<node> q;
node start(x1, y1, 0, "");
q.push(start);
node top;
while (1) {
if (q.empty()) {
flag = 0;
break;
}
top = q.front();
q.pop();
if (top.count > maxstep) {
flag = 0;
break;
}
if (top.x == endx && top.y == endy) {
break;
}
// 对于从队列中取出的节点进行三种操作
for (int i = 0; i < 3; i++) {
way(top, i, q);
}
}
if (flag == 0) {
cout << "-1" << endl;
}
else {
cout << top.count << " " << top.step << endl;
}
cin >> maxstep;
}
return 0;
}