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或者给出的操作不正确均不能得分。
果然是道行尚浅。这道题都让我WA了好多次。不过最后还是做出来了,就这样继续加油吧!
问题简述:
魔板,按照三种变换方法可以得到许多不同的魔板排列结果。给出一种想要的结果,输出固定步数内可得到结果的操作序列,若无法再固定步数内得到,则输出-1。
设计算法:
队列与回溯
思路:
穷举所有的操作结果,与目标态对比,如果相同则回溯输出。
用x表示1234,y表示8765位置
则 魔板1234
8765
对应x=1234 y=8765
以中间过程为例,去掉其中已经出现过的中间态(如去掉XAA 因为XAA = X)
转变成队列,每次穷举的结果是否入队需要进行判断,
若在队列中出现过相同的中间态则不入队。
直到结果与目标太相同时输出结果。
出现失误:
在解题过程中出现了很多错误,现在列出:
1、cur编号和pre编号没有对应,变成了cur 0123456……对应 pre 011122……。
2、pre的计数错误,应该是指针fp每向后挪一位pre++,即每次进行完三种操作ABC之后pre++
3、cur的计数错误,其实cur就是数组下标,每一个op自身的cur都不一样。
4、判断是否在规定步数之内错误,应该是在最后得到结果然后回溯的时候通过sop数组的最终大小来判断。
但是我一开始的想法是在进行ABC操作的时候就判断:三叉树每多一层就表示会多一个操作,以此来断定回溯最短距离是否在规定步数之内。同时又错误的吧pre当成了总步数,以致一错到底…………
代码:
/*
* main.cpp
*
* Created on: 2014年9月14日
* Author: xiangxiyun
*/
#include <iostream>
#define MAX 10000
using namespace std;
struct moban {
int x;
int y;
int pre;
char op;
};
moban m[MAX];
int sum;
int fpsum;
//执行入队操作以及判断是否达到目标态
bool comp(int tx, int ty, moban *cur) {
bool flag = true;
if (cur->x == tx && cur->y == ty) {
cur->pre = fpsum;
sum++;
m[sum] = *cur;
return true;
}
for (int i = 1; i <= sum; i++)
if (m[i].x == cur->x && m[i].y == cur->y) {
flag = false;
break;
}
if (flag == true) {
cur->pre = fpsum;
sum++;
m[sum] = *cur;
}
return false;
}
//A操作
moban opa(moban * fp) {
moban rp;
rp.x = fp->y;
rp.y = fp->x;
rp.op = 'A';
return rp;
}
//B操作
moban opb(moban * fp) {
moban rp;
rp.x = fp->x % 10 * 1000 + fp->x / 10;
rp.y = fp->y % 10 * 1000 + fp->y / 10;
rp.op = 'B';
return rp;
}
//C操作
moban opc(moban * fp) {
moban rp;
int i = (fp->x / 1000) * 1000;
int j = fp->x - i;
int a = j / 100;
int b = (j - a * 100) / 10;
int i1 = (fp->y / 1000) * 1000;
int j1 = fp->y - i1;
int c = j1 / 100;
int d = (j1 - c * 100) / 10;
rp.x = i + c * 100 + a * 10 + (fp->x % 10);
rp.y = i1 + d * 100 + b * 10 + (fp->y % 10);
rp.op = 'C';
return rp;
}
//回溯以及判断是否在规定步数之内
void printop(moban *rp, int max) {
char sop[10];
int j = 0;
int i = rp->pre;
sop[j] = rp->op;
while (i > 1) {
j++;
sop[j] = m[i].op;
i = m[i].pre;
}
if (j + 1 > max) {
cout << "-1" << endl;
} else {
cout << j + 1 << ' ';
for (int i = j; i >= 0; i--) {
cout << sop[i];
}
cout << endl;
}
}
//查找目标态
void search(int tx, int ty, int max) {
moban *fp = &m[1], *rp = new moban;
fpsum = 1;
bool flag = false;
while (true) {
*rp = opa(fp);
if (comp(tx, ty, rp)) {
flag = true;
break;
}
*rp = opb(fp);
if (comp(tx, ty, rp)) {
flag = true;
break;
}
*rp = opc(fp);
if (comp(tx, ty, rp)) {
flag = true;
break;
}
fp = fp + 1;
fpsum++;
}
if (flag == true)
printop(rp, max);
}
int main() {
int max = 0;
cin >> max;
while (max != -1) {
sum = 1;
m[1].x = 1234;
m[1].y = 8765;
m[1].pre = 0;
m[1].op = ' ';
int tx = 0, ty = 0;
int a, b, c, d;
cin >> a >> b >> c >> d;
tx = a * 1000 + b * 100 + c * 10 + d;
cin >> a >> b >> c >> d;
ty = a * 1000 + b * 100 + c * 10 + d;
search(tx, ty, max);
cin >> max;
}
return 0;
}