1150. 简单魔板
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge
Description
魔板由8个大小相同方块组成,分别用涂上不同颜色,用1到8的数字表示。
其初始状态是
1 2 3 4
8 7 6 5
对魔板可进行三种基本操作:
A操作(上下行互换):
8 7 6 5
1 2 3 4
B操作(每次以行循环右移一个):
4 1 2 3
5 8 7 6
C操作(中间四小块顺时针转一格):
1 7 2 4
8 6 3 5
用上述三种基本操作,可将任一种状态装换成另一种状态。
Input
输入包括多个要求解的魔板,每个魔板用三行描述。
第一行步数N(不超过10的整数),表示最多容许的步数。
第二、第三行表示目标状态,按照魔板的形状,颜色用1到8的表示。
当N等于-1的时候,表示输入结束。
Output
对于每一个要求解的魔板,输出一行。
首先是一个整数M,表示你找到解答所需要的步数。接着若干个空格之后,从第一步开始按顺序给出M步操作(每一步是A、B或C),相邻两个操作之间没有任何空格。
注意:如果不能达到,则M输出-1即可。
Sample Input
4 5 8 7 6 4 1 2 3 3 8 7 6 5 1 2 3 4 -1
Sample Output
2 AB 1 A 评分:M超过N或者给出的操作不正确均不能得分。
Problem Source
ZSUACM Team Member
#include <iostream> #include <vector> #include <stack> using namespace std; //定义一个魔方的结构体 typedef struct mf { int up; //魔方上行数字 int down; //魔方下行数字 char op; //由该操作得到该魔方 int pre; //记录该魔方的前一个魔方,即在三叉树中的父节点在队列中的下标,用于回溯输出最短到达该目的魔方所经过的变换,此设计很关键 } MF; //比较待插入的魔方是否已经在队列中存在 bool cmp(vector<MF> &mfs, MF mf, char op, int pre) { for (int i = 0; i < mfs.size(); i++) { if (mfs[i].up == mf.up && mfs[i].down == mf.down) { //如果队列中已经存在该待插入魔方,则不进行插入,即对三叉树进行剪枝 return false; } } //队列中不存在该魔方,插入 mf.pre = pre; mf.op = op; mfs.push_back(mf); return true; } //由于一共有三种操作,所以为三叉树 //操作A 1234 8765 -> 8765 1234 通过result引用来返回进行操作后的魔方 char opA(MF mf, int pre, MF &result) { int m = mf.up; int n = mf.down; mf.up = n; mf.down = m; result = mf; result.pre = pre; result.op = ‘A‘; return ‘A‘; } //操作B 1234 8765 -> 4123 5876 char opB(MF mf, int pre, MF &result) { int up_first = (mf.up % 10) * 1000; int down_first = (mf.down % 10) * 1000; int up_last = ((mf.up - (mf.up / 1000) * 1000) - ((mf.up - (mf.up / 1000) * 1000) / 100) * 100) / 10; int down_last = ((mf.down - (mf.down / 1000) * 1000) - ((mf.down - (mf.down / 1000) * 1000) / 100) * 100) / 10; mf.up = up_first + (mf.up / 1000) * 100 + ((mf.up - (mf.up / 1000) * 1000) / 100) * 10 + up_last; mf.down = down_first + (mf.down / 1000) * 100 + ((mf.down - (mf.down / 1000) * 1000) / 100) * 10 + down_last; result = mf; result.pre = pre; result.op = ‘B‘; return ‘B‘; } //操作C 1234 5678 -> 1624 5738 char opC(MF mf, int pre, MF &result) { int i1 = (mf.up - (mf.up / 1000) * 1000) / 100; int i2 = ((mf.up - (mf.up / 1000) * 1000) - i1 * 100) / 10; int j1 = (mf.down - (mf.down / 1000) * 1000) / 100; int j2 = ((mf.down - (mf.down / 1000) * 1000) - j1 * 100) / 10; mf.up = (mf.up / 1000) * 1000 + j1 * 100 + i1 * 10 + mf.up % 10; mf.down = (mf.down / 1000) * 1000 + j2 * 100 + i2 * 10 + mf.down % 10; result = mf; result.pre = pre; result.op = ‘C‘; return ‘C‘; } int main () { int max; while(cin >> max && max != -1) { int find_length = 0; int target[8]; int value; for (int i = 0; i < 8; i++) { cin >> value; target[i] = value; } vector<MF> mfs; stack<char> ops; int fp = 0, rp = 0;//fp为头指针,指向当前正在处理的节点,rp为队列尾指针,指向入队的节点 bool success = false; int up = target[0] * 1000 + target[1] * 100 + target[2] * 10 + target[3]; //目标魔方的上行 int down = target[7] + target[6] * 10 + target[5] * 100 + target[4] * 1000; //目标魔方的下行 MF mf; mf.up = 1234; mf.down = 8765; mf.op = ‘ ‘; mf.pre = -1; mfs.push_back(mf); //若未找到,则循环查找 while (mfs[fp].up != up || mfs[fp].down != down) { //对魔方进行操作,头指针执行正在进行操作的魔方,尾指针执行操作后进入队列的魔方 MF result; char a = opA(mfs[fp], fp, result); //每次进行一次变换后,查看是否为目标态 if (result.up == up && result.down == down) { //发现目标魔方,则根据pre来回溯得到操作序列 while (result.pre != -1) { ops.push(result.op); find_length++; result = mfs[result.pre];//回溯 } success = true; break; } else if (cmp(mfs, result, a, fp)) {//如果队列中没有该魔方,该魔方进队 rp++; //尾指针递增 } char b = opB(mfs[fp], fp, result); if (result.up == up && result.down == down) { //发现目标魔方,则根据pre来回溯得到操作序列 while (result.pre != -1) { ops.push(result.op); find_length++; result = mfs[result.pre];//回溯 } success = true; break; } else if (cmp(mfs, result, b, fp)) { rp++; } char c = opC(mfs[fp], fp, result); if (result.up == up && result.down == down) { //发现目标魔方,则根据pre来回溯得到操作序列 while (result.pre != -1) { ops.push(result.op); find_length++; result = mfs[result.pre];//回溯 } success = true; break; }else if (cmp(mfs, result, c, fp)) { rp++; } fp++; //头指针递增 } //如果不能在指定步数内找到,则输出-1 if (find_length > max) { cout << -1 << endl; } else { cout << find_length << " "; while (!ops.empty()) { //找到输出由初态变为目标态的过程 cout << ops.top(); ops.pop(); } cout << endl; } } return 0; }
时间: 2024-10-29 14:50:03