The Rotation Game(IDA*)

The rotation game uses a # shaped board, which can hold 24 pieces of square blocks (see Fig.1). The blocks are marked with symbols 1, 2 and 3, with exactly 8 pieces of each kind.
Initially, the blocks are placed on the board randomly. Your task is to move the blocks so that the eight blocks placed in the center square have the same symbol marked. There is only one type of valid move, which is to rotate one of the four lines, each consisting of seven blocks. That is, six blocks in the line are moved towards the head by one block and the head block is moved to the end of the line. The eight possible moves are marked with capital letters A to H. Figure 1 illustrates two consecutive moves, move A and move C from some initial configuration.
在这里插入图片描述
Input
The input consists of no more than 30 test cases. Each test case has only one line that contains 24 numbers, which are the symbols of the blocks in the initial configuration. The rows of blocks are listed from top to bottom. For each row the blocks are listed from left to right. The numbers are separated by spaces. For example, the first test case in the sample input corresponds to the initial configuration in Fig.1. There are no blank lines between cases. There is a line containing a single ‘0’ after the last test case that ends the input.
Output
For each test case, you must output two lines. The first line contains all the moves needed to reach the final configuration. Each move is a letter, ranging from ’A’ to‘‘H’, and there should not be any spaces between the letters in the line. If no moves are needed, output `No moves needed’ instead. In the second line, you must output the symbol of the blocks in the center square after these moves. If there are several possible solutions, you must output the one that uses the least number of moves. If there is still more than one possible solution, you must output the solution that is smallest in dictionary order for the letters of the moves. There is no need to output blank lines between cases.
Sample Input
1 1 1 1 3 2 3 2 3 1 3 2 2 3 1 2 2 2 3 1 2 1 3 3
1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
0
Sample Output
AC
2
DDHH
2

能看出这个题是需要一步一步搜索答案的,看了别人的才知道用IDA*,就是一边深搜一边广搜
之前做过一个,也有一点点小模版吧
1、IDDFS:指定递归深度,每一次DFS都不超过这个深度
2、估价函数:我一开始不会写,结果不写还不行,时间限制,必须要用他剪枝。对当前局面作出估计,如果当前的值用最快的方式都不能符合要求,就停止用这个值,继续DFS
3、判断结束条件:这个题是,当中间八个数都相同时,递归结束

然后特殊的地方在于旋转方式,把八种情况都分别列出,然后每种情况都搜搜,最后用一个数组记录输出方式

这个题,用估价函数得到距离目标节点的最小可能距离,当前状态下,中间八个格出现次数最多的数的次数记为m,每一次操作最多能使这个数字出现次数+1(最优的时候)(如果最后中间的数字不是这个数字,步数会更多)。所以 (8 - m) 就是最快的情况下的剩余步数。

??写完评估函数还错
把判断步数为0的情况放前面就行了。。

可以把八种移动方法,写成一个二维数组,然后写成一个函数?看不懂可以先看最后的直接写法,容易理解

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iomanip>

using namespace std;
int depth,a[25],n,x,y;
int p[8][7]=
{
	1,3,7,12,16,21,23,
	2,4,9,13,18,22,24,
	11,10,9,8,7,6,5,
	20,19,18,17,16,15,14,
	24,22,18,13,9,4,2,
	23,21,16,12,7,3,1,
	14,15,16,17,18,19,20,
	5,6,7,8,9,10,11
};
int b[8]={7,8,9,12,13,16,17,18};//这个是用来判断中间8位数的
string s;
int least()//评估函数
{
    int minn=8;
    for(int i=1;i<=3;i++)
    {
        y=0;
        for(int j=0;j<8;j++)
        {
            if(a[b[j]]!=i) y++;
        }
        minn=min(minn,y);
    }
    return minn;
}
bool right()//判断函数
{
    for(int i=1;i<8;i++)
    {
        if(a[b[i]]!=a[b[0]]) return 0;
    }
    return 1;
}
bool IDA(int pos,int depth)
{
    if(right())//判断函数判断,符合条件
    {
        if(pos==0) cout<<"No moves needed";
        else
        {
            for(int i=0; i<pos; i++)
                cout<<s[i];
        }
        return 1;
    }
    if(pos+least()>depth) return 0;//IDDFS
    for(int i=0;i<8;i++)
    {

       int temp[25];
       memcpy(temp,a,sizeof(a));
       x=a[p[i][0]];//i代表了八个字母,x是这种方法的第一个位置
       for(int j=0;j<6;j++)
       {
           a[p[i][j]]=a[p[i][j+1]];
       }
       a[p[i][6]]=x;
       s[pos]=i+'A';
       if(IDA(pos+1,depth))  return 1;
       memcpy(a,temp,sizeof(temp));
    }
    return 0;
}
int main()
{
    std::ios::sync_with_stdio(false);
    while(cin>>a[1]&&a[1])
    {
        for(int i=2;i<=24;i++)
        {
            cin>>a[i];
        }
        for(depth=1;;depth++)
        {
            if(IDA(0,depth)) break;//每次都从0开始,到depth层结束
        }
        cout<<endl;
        cout<<a[7]<<endl;//中间值
    }
	return 0;
}

这个是直接移动方法,不太舍得删

x=a[1];a[1]=a[3];a[3]=a[7];a[7]=a[12];a[12]=a[16];a[16]=a[21];a[21]=a[23];a[23]=x;
s[pos]='A';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[2];a[2]=a[4];a[4]=a[9];a[9]=a[13];a[13]=a[18];a[18]=a[22];a[22]=a[24];a[24]=x;
s[pos]='B';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[11];a[11]=a[10];a[10]=a[9];a[9]=a[8];a[8]=a[7];a[7]=a[6];a[6]=a[5];a[5]=x;
s[pos]='C';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[20];a[20]=a[19];a[19]=a[18];a[18]=a[17];a[17]=a[16];a[16]=a[15];a[15]=a[14];a[14]=x;
s[pos]='D';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[24];a[24]=a[22];a[22]=a[18];a[18]=a[13];a[13]=a[9];a[9]=a[4];a[4]=a[2];a[2]=x;
s[pos]='E';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[23];a[23]=a[21];a[21]=a[16];a[16]=a[12];a[12]=a[7];a[7]=a[3];a[3]=a[1];a[1]=x;
s[pos]='F';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[14];a[14]=a[15];a[15]=a[16];a[16]=a[17];a[17]=a[18];a[18]=a[19];a[19]=a[20];a[20]=x;
s[pos]='G';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));

x=a[5];a[5]=a[6];a[6]=a[7];a[7]=a[8];a[8]=a[9];a[9]=a[10];a[10]=a[11];a[11]=x;
s[pos]='H';
if(IDA(pos+1,depth)) return 1;
memcpy(a,temp,sizeof(temp));
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值