Uva1343 The Rotation Game 【IDA*】【例题7-12】

题目:The Rotation Game

题意:给出一个形状(原题有图)的棋盘上分别有8123,要往AH方向旋转棋盘,使中间8个方格数字相同。

有8个移动方向,朝向哪个方向移动就是对应的整条都向本方向移动一格,第一位补到最后一位。输出最少的移动方向序列,并输出中间数字为几。

思路:看了紫书的分析后并没有思路。。。最后还是看了代码库的IDA*求解的

(1)画图:将8个方向的的数字在输入的一维数组对应下标的位置分别存放到二维数组中,只需写出ABCD,EFGH是ABCD的反方向;

(2)枚举深度进行dfs;

(3)dfs搜索:枚举8个方向,将当前方向保存到一个结果数组中,枚举到某个方向后,在这个方向的数字进行移动,然后继续递归,每次递归后需将改变的回溯,利用反方向再次移动即可。直到找到后输出移动方向序列即可;

(4)剪枝:看下估值函数h():计算当前中间数字相同最多即不同最少的一个值;然后判断当前深度d + h() 是否小于 枚举深度maxd  ,小于的话说明可以再maxd下得出结果,否则都大于maxd了,再搜索也不可能找到,直接剪枝掉!

参考:紫书代码仓库

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int line[8][7]={//表示各元素在输入的位置
  { 0, 2, 6,11,15,20,22}, // A
  { 1, 3, 8,12,17,21,23}, // B
  {10, 9, 8, 7, 6, 5, 4}, // C
  {19,18,17,16,15,14,13}, // D
};
const int rev[8] = {5, 4, 7, 6, 1, 0, 3, 2}; //分别表示F E H G B A D C
const int center[8] = {6, 7, 8, 11, 12, 15, 16, 17};//中间位置
int a[24];
char ans[1000];
bool is_fin(){//是否达到目标状态
    for(int i=0;i<8;i++)
        if(a[center[0]] != a[center[i]]) return false;
    return true;
}
int diff(int target){//计算当前差几个达到目标
    int cot = 0;
    for(int i=0;i<8;i++)
        if(a[center[i]] != target) cot++;
    return cot;
}
void moved(int i){//向i方向移动
    int temp = a[line[i][0]];
    for(int j=0;j<6;j++) a[line[i][j]] = a[line[i][j+1]];
    a[line[i][6]] = temp;
}
int h(){//估值函数
    return min(min(diff(1),diff(2)),diff(3));
}
bool dfs(int d,int maxd){
    if(is_fin()){//达到目标
        ans[d] = '\0';
        printf("%s\n",ans);
        return true;
    }
    if(d + h() > maxd) return false;//剪枝
    for(int i=0;i<8;i++){
        ans[d] = i + 'A';
        moved(i);//向i方向移动
        if(dfs(d+1,maxd)) return true;
        moved(rev[i]);//还原,回溯

    }
    return false;
}
void solve(){
    for(int maxd=1; ;maxd++)
        if(dfs(0,maxd)) break;
}
void init(){
    for(int i=4;i<8;i++)//EFGH由ABCD得出
        for(int j=0;j<7;j++) line[i][j] = line[rev[i]][6-j];
}
int main()
{
    init();
    while(scanf("%d",&a[0]) == 1 && a[0]){
        for(int i=1;i<24;i++) scanf("%d",&a[i]);
        if(is_fin()) printf("No moves needed\n");
        else solve();
        printf("%d\n",a[6]);//最终中间的数字
    }
    return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值