hdu 1667 The Rotation Game(2004 Asia Regional Shanghai)

题目大意

有一个神奇的游戏,有一个#字形的界面。
每次有八种操作,如图:
题目大意
定义最终状态为中间八个格子都是同一个数。
现在给出一种界面,问最少几步可以到达最终状态。
第一行输出每次操作。如果有多组解,输出字典序最小的一组,如果不用移动,输出“No moves needed”。
第二行输出最终状态中间八个格子的数字。

题解

输入格式比较坑,还不知道有什么好方法,于是我就直接一个一个格子读入了。
显然直接爆搜是不行的。
既然要优化,首先要确定用深搜还是广搜。
如果用广搜,貌似状态不怎么好记,不过貌似看到一种神奇的做法,先枚举中间最后是什么数字,然后记录这些数字的位子作为状态,直接广搜。暂时没想明白。
于是我用了深搜。
我直接人工模拟每个操作,然而实际上这些操作是可以打表的,所以我代码比较冗长。
这种寻找最小步数的题,可以使用迭代加深弥补dfs的不足。
然而这样还是过不了这题。
于是转向去寻找一个启发式函数,进行idA*。
一开始,我把每个位置里中心八个块的最短距离加起来,就可以得到每个数字的一个启发值,就取最小的那个。
但是这样是错的,因为一次移动可能导致好几个块的最短距离减小。
所以应该求最大值,加了这个优化之后,代码就可以过了。

#include <cstdio>
#include <iostream>
#include <cctype>
#include <string>
#include <algorithm>
using namespace std;
int A[10][10],H[10][10];
inline void rd(int&res){
    res=0;char c;
    while(c=getchar(),!isdigit(c));
    do res=res*10+(c^48);
    while(c=getchar(),isdigit(c));
}
int ans=0,sz;
char res[10];
int H_function(){
    int tmp[4]={0};
    int mx[4]={0};
    for(int i=1;i<=7;i++)
        mx[A[3][i]]=max(mx[A[3][i]],H[i][3]);
    for(int i=1;i<4;i++)
        tmp[i]+=mx[i],mx[i]=0;
    for(int i=1;i<=7;i++)
        mx[A[5][i]]=max(mx[A[5][i]],H[i][5]);
    for(int i=1;i<4;i++)
        tmp[i]+=mx[i],mx[i]=0;
    for(int i=1;i<=7;i++)
        mx[A[i][3]]=max(mx[A[i][3]],H[3][i]);
    for(int i=1;i<4;i++)
        tmp[i]+=mx[i],mx[i]=0;
    for(int i=1;i<=7;i++)
        mx[A[i][5]]=max(mx[A[i][5]],H[5][i]);
    for(int i=1;i<4;i++)
        tmp[i]+=mx[i],mx[i]=0;
    return min(tmp[1],min(tmp[2],tmp[3]));
}
void dfs(int dep){
    if(ans) return;
    if(dep<0) return;
    int h=H_function();
    if(h==0){
        ans=A[3][3];
        return;
    }
    if(dep<h) return;
    int B[8][8]={0};
    for(int i=1;i<=7;i++)
        for(int j=1;j<=7;j++)
            B[i][j]=A[i][j];
    //A
    //
    A[3][7]=B[3][1];
    for(int i=1;i<7;i++)
        A[3][i]=B[3][i+1];
    dfs(dep-1);
    if(ans){
        res[sz++]='A';
        return;
    }
    for(int i=1;i<=7;i++)
        A[3][i]=B[3][i];
    //
    A[5][7]=B[5][1];
    for(int i=1;i<7;i++)
        A[5][i]=B[5][i+1];
    dfs(dep-1);
    if(ans){
        res[sz++]='B';
        return;
    }
    for(int i=1;i<=7;i++)
        A[5][i]=B[5][i];
    //
    for(int i=2;i<=7;i++)
        A[i][3]=B[i-1][3];
    A[1][3]=B[7][3];
    dfs(dep-1);
    if(ans){
        res[sz++]='C';
        return;
    }
    for(int i=1;i<=7;i++)
        A[i][3]=B[i][3];
    //
    for(int i=2;i<=7;i++)
        A[i][5]=B[i-1][5];
    A[1][5]=B[7][5];
    dfs(dep-1);
    if(ans){
        res[sz++]='D';
        return;
    }
    for(int i=1;i<=7;i++)
        A[i][5]=B[i][5];
    //
    A[5][1]=B[5][7];
    for(int i=2;i<=7;i++)
        A[5][i]=B[5][i-1];
    dfs(dep-1);
    if(ans){
        res[sz++]='E';
        return;
    }
    for(int i=1;i<=7;i++)
        A[5][i]=B[5][i];
    //
    A[3][1]=B[3][7];
    for(int i=2;i<=7;i++)
        A[3][i]=B[3][i-1];
    dfs(dep-1);
    if(ans){
        res[sz++]='F';
        return;
    }
    for(int i=1;i<=7;i++)
        A[3][i]=B[3][i];
    //
    for(int i=1;i<7;i++)
        A[i][5]=B[i+1][5];
    A[7][5]=B[1][5];
    dfs(dep-1);
    if(ans){
        res[sz++]='G';
        return;
    }
    for(int i=1;i<=7;i++)
        A[i][5]=B[i][5];
    //
    for(int i=1;i<7;i++)
        A[i][3]=B[i+1][3];
    A[7][3]=B[1][3];
    dfs(dep-1);
    if(ans){
        res[sz++]='H';
        return;
    }
    for(int i=1;i<=7;i++)
        A[i][3]=B[i][3];
}
void solve(){
    ans=0;
    rd(A[5][1]);rd(A[3][2]);rd(A[5][2]);
    for(int i=1;i<=7;i++)
        rd(A[i][3]);
    rd(A[3][4]);rd(A[5][4]);
    for(int i=1;i<=7;i++)
        rd(A[i][5]);
    rd(A[3][6]);rd(A[5][6]);
    rd(A[3][7]);rd(A[5][7]);
    sz=0;
    for(int i=0;;i++){
        dfs(i);
        if(ans){
            if(sz){
                for(int w=sz-1;w>=0;w--)
                    printf("%c",res[w]);
                puts("");
            }else puts("No moves needed");
            printf("%d\n",ans);
            return;
        }
    }
}
int main(){
    H[1][3]=H[1][5]=H[3][1]=H[5][1]=H[7][3]=H[7][5]=H[3][7]=H[5][7]=2;
    H[2][3]=H[2][5]=H[3][2]=H[5][2]=H[6][3]=H[6][5]=H[3][6]=H[5][6]=1;
    while(rd(A[3][1]),A[3][1]) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值