【poj 2286】The Rotation Game 题意&题解&代码(C++)

63 篇文章 0 订阅
56 篇文章 2 订阅

题目链接:
http://poj.org/problem?id=2286
题意:
刚开始给出如图所示的一个井字形棋盘,每个棋盘上放有一个数,这个数一定是1,2,3中的一个,按图所示给列标号,现在有8种操作,每种操作分别为ABCDEFGH对应图中标号,每次操作相当于将这一列往标号的方向滚动一格,题上图示为先操作A,再操作C,问最少几次操作使得中心的8个格子数字相同,输出最后中心的数字,输出操作方式,不用操作则输出 No moves needed
题解:
IDA*搜索,这道题的估价比较直白,直接找中心八个数中的数量最多的数出现的次数 pri ,然后若当前步数 dep+8 - pri > ans 则不继续往下搜。

注意刚开始给棋盘标号,一定要细心,我就因为一个数字标错调了半个小时,QAQ。

还有一个很大的优化点,那就是按题上标号时,如果上一步操作了A,那么这步一定不要操作G,因为会抵消上步操作的作用,而刚开始我想着用sum[i]表示操作i的总次数,操作i一定不会超过7次,这样想着去优化,结果优化效果并不明显直接TLE。

代码:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
int tt,s[25],cnt[4],ans,path[40];
int check(int *w)
{
    if (w[7]==w[8]&&w[8]==w[9]&&w[9]==w[13]&&w[13]==w[12])
    if (w[12]==w[16]&&w[16]==w[17]&&w[17]==w[18])
    {
        tt=w[9];
        return 1;
    }
    return 0;
}
//此处标号一定小心!!!!
int pan[8][7]={ {1, 3, 7,12,16,21,23},   //A
        {2, 4, 9,13,18,22,24},     //B
        {11,10,9, 8, 7, 6, 5},     //C  
        {20,19,18,17,16,15,14},    //D
        {24,22,18,13, 9, 4, 2},    //E
        {23,21,16,12, 7, 3, 1},    //F
        {14,15,16,17,18,19,20},    //G
        {5, 6, 7, 8, 9, 10,11}};       //H
int fan[8]={5,4,7,6,1,0,3,2};
int num[8]={7,7,7,7,7,7,7,7};
void rotate(int x,int *k)
{
    int tmp=k[pan[x][0]];
    for (int i=0;i<6;i++)
    k[pan[x][i]]=k[pan[x][i+1]];
    k[pan[x][6]]=tmp;
}
int dfs(int dep,int *now,int *mov,int pre)
{
    if (check(now)) return 1;
    cnt[1]=0;cnt[2]=0;cnt[3]=0;
    cnt[now[7]]++;cnt[now[8]]++;cnt[now[9]]++;cnt[now[13]]++;
    cnt[now[12]]++;cnt[now[16]]++;cnt[now[17]]++;cnt[now[18]]++;
    int pri=max(cnt[3],max(cnt[1],cnt[2]));
    if (dep+8-pri>ans) 
    return 0;

    for (int i=0;i<8;i++)
    if (fan[i]!=pre)
    {
        rotate(i,now);
        mov[dep+1]=i;
        if (dfs(dep+1,now,mov,i))return 1;
        rotate(fan[i],now);
    }
    return 0;
}
int main()
{
    while(scanf("%d",&s[1]))
    {
        if (s[1]==0) return 0;
        for (int i=2;i<=24;i++)
        scanf("%d",&s[i]);
        if (check(s)) 
        {
            printf("No moves needed\n");
            printf("%d\n",s[9]);
            continue;
        }
        for (int i=1;i<=29;i++)
        {
            ans=i;
            int hh[25];
            for (int i=1;i<=24;i++) hh[i]=s[i];
            if (dfs(0,hh,path,-1)) break;
        }
        for (int i=1;i<=ans;i++)
        {
            char c=path[i]+'A';
            printf("%c",c);
        }
        printf("\n");
        printf("%d\n",tt);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值