【C++心路历程34】【HDU1667】【POJ2286】【UVA1343紫书210例题】the rotation game

【问题描述】

  如下图所示形状的棋盘上分别有8个1,8个2,8个3。在图上标明了8种旋转方式:每种旋转方式包含旋转方向和旋转的是拿一列或行。
  
  (没有图 很尴尬)



  现在需要把棋盘经过若干次旋转,使得中间8个方格中的数字相同,例如下图,先进行一次A方式的旋转,再进行一次C方式的旋转后,棋盘中间的8个方格的数字都是2。
  
  现在需要你对给出的棋盘的初始状态和目标状态,需要旋转最少的次数从初始状态变到目标状态,如果有多种旋转方式,输出字典序最小的。

【输入格式】

  最多不超过30组数据,每组数据含一行,表示棋盘的初始状态,包含24个整数:1,2,3,对应棋盘从上到下,从左到右的每个格子的数字。输入以0结束。 

【输出格式】

  每组数据输出2行,第一行字典序最小的旋转操作序列(如果不需要任何操作,请输出“No moves needed”),第二行为棋盘目标状态中间8个方格中的数字。

【输入样例】

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

【输出样例】

AC
2
DDHH
2

【样例解释】

每个测试点不超过30组数据。

【分析】
紫书上爆搜蛮好,这里用A*算法写。
因为题目所求“最少步数”,正好符合DFSID模型。
主程序:

void solve()
{
    if(check()) 
    {
        printf("No moves needed\n");
        printf("%d\n",a[3][3]);
        return;
    }
    for(maxd=0;;maxd++)
    {
        if(DFSID(1)) break;
    }
    for(int i=1;i<=maxd;i++)
    {
        printf("%c",ans[i]);
    }   
    printf("\n%d\n",a[3][3]);
}

//DFSID
//小技巧:恢复A操作可视为F操作,以此类推,可以少写许多函数并节省空间

bool DFSID(int i)
{
    if(i>maxd)
    {
        if(check()) return true;
        return false;
    }
    //估价

    //依次处理ABCDEFGH操作,并恢复
    //小技巧:恢复A操作可视为F操作,以此类推,可以少写许多函数并节省空间
    return false;

估价函数分析:因为每次变换最多只改变一个错误位置,所以在中间8个数中,现在将最大的数视为“正确的”,设有maxd个,那也得至少改变8-maxd次才有可能达到目标状态。

//  估价函数:每次移动最多改变1个错误的位置 
    int vis[4]={0,0,0,0};
    vis[a[3][3]]++;vis[a[3][5]]++;
    vis[a[3][4]]++;vis[a[4][5]]++;
    vis[a[5][3]]++;vis[a[5][4]]++;
    vis[a[5][5]]++;vis[a[4][3]]++;
    int h=8-max(vis[1],max(vis[3],vis[2]));//错误的数目 
    if(i-1+h>maxd) return false;
    //前i-1步 和至少还要走h步(估价函数)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值