hdu 1667 /poj 2286 The Rotation Game(经典迭代加深)

The Rotation Game
Time Limit: 15000MS Memory Limit: 150000K
Total Submissions: 6081 Accepted: 2048

Description

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
题意:一个“井”字形的玩具,上面有三种数字1、2、3,给出8种操作方式,A表示将第一个竖着的列循环上移一格,并且A和F是一个逆操作,B、C、D...的操作方式依此类推,初始状态给定,目标状态是中间8个数字相同。问最少的操作方式,并且要求给出操作的序列,步数一样的时候选择字典序最小的输出。图中的操作序列为AC。

思路:一开始的总体思路就是对的,不过有一个很难发现的坑坑了我一下午啊....

我们去枚举深度,在当前深度下进行DFS找有没有一种序列满足中间八个数字一样即可

注意有两个剪枝,第一个是这一次选择的字母不能和上一次对应,比如上一次选择了A,这次就不能选择F

第二个是因为每次移动在中间8个格子里最多多一个我们想要的数字,所以当前步数+尚未有我们想要的数字的格子数>深度的时候就return

这是个很高效的剪枝,15s的题可以再120ms过

另外,还有一个坑了我一下午的坑,我不知道其他人会不会跟我有一样的想法,这里姑且分享一下。

不能枚举数字,原因在于答案是要求字典序最小。而我们枚举数字找到一个合法的情况就break掉了,那么有可能出现就是你现在找到的合法情况中间数字是1,而有一种字典序更小的操作方式中间数字是2.如果你的思路和我一样,说到这里应该懂了吧。所以我们只要枚举深度就可以了,每次判断就判断三个数字即可。在当前深度下有一种能达到八个数字都相等就一定是字典序最小的了。如果你一定要枚举中间数字也不是不行,不过要把1~3三个数字都枚举完,有多个答案就取操作序列字典序小的。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int a[50],num[4];
char ans[1000],cnt;
int qian,hou;
void swap1(int &a1,int &a2,int &a3,int &a4,int &a5,int &a6,int &a7)
{
    int temp=a1;
    a1=a2,a2=a3,a3=a4,a4=a5,a5=a6,a6=a7,a7=temp;
}
int check(int *b)
{
    int k=b[7];
    if(k==b[8]&&k==b[9]&&k==b[12]&&k==b[13]&&k==b[16]&&k==b[17]&&k==b[18]) return 1;
    return 0;
}
int solve(int *b)
{
    int c[4];
    c[1]=c[2]=c[3]=0;
    c[b[7]]++,c[b[8]]++,c[b[9]]++;
    c[b[12]]++,c[b[13]]++;
    c[b[16]]++,c[b[17]]++,c[b[18]]++;
    return max(c[1],max(c[2],c[3]));
}
int dfs(int dep,int now_dep,int last,int *b)
{
    if(8-solve(b)+now_dep>dep||now_dep==dep) return 0;
    if(last!=6)
    {
        swap1(b[1],b[3],b[7],b[12],b[16],b[21],b[23]);
        if(check(b))
        {
            ans[++cnt]='A';
            return 1;
        }
        if(dfs(dep,now_dep+1,1,b))
        {
            ans[++cnt]='A';
            return 1;
        }
        swap1(b[23],b[21],b[16],b[12],b[7],b[3],b[1]);
    }
    if(last!=5)
    {
        swap1(b[2],b[4],b[9],b[13],b[18],b[22],b[24]);
        if(check(b))
        {
            ans[++cnt]='B';
            return 1;
        }
        if(dfs(dep,now_dep+1,2,b))
        {
            ans[++cnt]='B';
            return 1;
        }
        swap1(b[24],b[22],b[18],b[13],b[9],b[4],b[2]);
    }
    if(last!=8)
    {
        swap1(b[11],b[10],b[9],b[8],b[7],b[6],b[5]);
        if(check(b))
        {
            ans[++cnt]='C';
            return 1;
        }
        if(dfs(dep,now_dep+1,3,b))
        {
            ans[++cnt]='C';
            return 1;
        }
        swap1(b[5],b[6],b[7],b[8],b[9],b[10],b[11]);
    }
    if(last!=7)
    {
        swap1(b[20],b[19],b[18],b[17],b[16],b[15],b[14]);
        if(check(b))
        {
            ans[++cnt]='D';
            return 1;
        }
        if(dfs(dep,now_dep+1,4,b))
        {
            ans[++cnt]='D';
            return 1;
        }
        swap1(b[14],b[15],b[16],b[17],b[18],b[19],b[20]);
    }
    if(last!=2)
    {
        swap1(b[24],b[22],b[18],b[13],b[9],b[4],b[2]);
        if(check(b))
        {
            ans[++cnt]='E';
            return 1;
        }
        if(dfs(dep,now_dep+1,5,b))
        {
            ans[++cnt]='E';
            return 1;
        }
        swap1(b[2],b[4],b[9],b[13],b[18],b[22],b[24]);
    }
    if(last!=1)
    {
        swap1(b[23],b[21],b[16],b[12],b[7],b[3],b[1]);
        if(check(b))
        {
            ans[++cnt]='F';
            return 1;
        }
        if(dfs(dep,now_dep+1,6,b))
        {
            ans[++cnt]='F';
            return 1;
        }
        swap1(b[1],b[3],b[7],b[12],b[16],b[21],b[23]);
    }
    if(last!=4)
    {
        swap1(b[14],b[15],b[16],b[17],b[18],b[19],b[20]);
        if(check(b))
        {
            ans[++cnt]='G';
            return 1;
        }
        if(dfs(dep,now_dep+1,7,b))
        {
            ans[++cnt]='G';
            return 1;
        }
        swap1(b[20],b[19],b[18],b[17],b[16],b[15],b[14]);
    }
    if(last!=3)
    {
        swap1(b[5],b[6],b[7],b[8],b[9],b[10],b[11]);
        if(check(b))
        {
            ans[++cnt]='H';
            return 1;
        }
        if(dfs(dep,now_dep+1,8,b))
        {
            ans[++cnt]='H';
            return 1;
        }
        swap1(b[11],b[10],b[9],b[8],b[7],b[6],b[5]);
    }
    return 0;
}
int main()
{
    int b[50];
    while(~scanf("%d",&a[1])&&a[1])
    {
        for(int i=2; i<=24; i++)
            scanf("%d",&a[i]);
        int flag=0;
        memset(num,0,sizeof(num));
        num[a[7]]++,num[a[8]]++,num[a[9]]++;
        num[a[12]]++,num[a[13]]++;
        num[a[16]]++,num[a[17]]++,num[a[18]]++;
        if(num[1]==8||num[2]==8||num[3]==8)
        {
            printf("No moves needed\n%d\n",a[7]);
            continue;
        }
        for(int dep=1; !flag; dep++)
        {
            cnt=0;
            memcpy(b,a,sizeof(b));
            if(dfs(dep,0,0,b))
            {
                flag=1;
                for(int j=cnt; j>0; j--)
                    printf("%c",ans[j]);
                printf("\n%d\n",b[7]);
                break;
            }
        }
    }
    return 0;
}






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值