sicily1150 & 魔板

1150. 简单魔板

Constraints

Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge

Description

魔板由8个大小相同方块组成,分别用涂上不同颜色,用18的数字表示。

其初始状态是

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的整数),表示最多容许的步数。

第二、第三行表示目标状态,按照魔板的形状,颜色用18的表示。

当N等于-1的时候,表示输入结束。

Output

对于每一个要求解的魔板,输出一行。

首先是一个整数M,表示你找到解答所需要的步数。接着若干个空格之后,从第一步开始按顺序给出M步操作(每一步是ABC),相邻两个操作之间没有任何空格。

注意:如果不能达到,则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)位置来对应。魔板编号如下:

  用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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值