SP4546 ANARC08A - Tobo or not Tobo IDA*

题意:
旋转A,B,C,D,一并带着相邻的四个数字旋转。
给定初始状态,求在给定次数下,能否到达如figure(a)的状态。
输入:十位字符串,第一位为给定次数,后九位为初始状态。

提交次数:3次(然鹅洛谷上的remotejudge一直CE)
错误:mxd初值设成了1,qwq
 
题解:
思路:搜索,IDA*
估价函数$h()$:每个数到应到位置的曼哈顿距离$\frac {\sum dis[i]}{4}$
正确性:每次旋转至多将这个值减少$4$
 
代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define R register int
using namespace std;
#define ull unsigned long long
#define ll long long
#define pause (for(R i=1;i<=10000000000;++i))
const int N=10;
const int p[4]={1,2,4,5};
char s[N];
const int d[N][2]={
{0,0},
{1,1},
{1,2},
{1,3},
{2,1},
{2,2},
{2,3},
{3,1},
{3,2},
{3,3}
};
int mp[N],mxd;
inline void rot(int* a,int d) {
    memmove(a+d+1,a+1,sizeof(int)*4);
    if(d==1) a[1]=a[5],a[5]=0;
    if(d==-1) a[4]=a[0],a[0]=0;
}
inline void change(int pos,int d) {
    R a[6];
    a[1]=mp[pos],a[2]=mp[pos+1],a[3]=mp[pos+4],a[4]=mp[pos+3];
    rot(a,d);
    mp[pos]=a[1],mp[pos+1]=a[2],mp[pos+4]=a[3],mp[pos+3]=a[4];
}
inline int h() { R ret=0;
    for(R i=1;i<=9;++i) {
        ret+=abs(((i-1)/3+1)-d[mp[i]][0])+abs((i-1)%3+1-d[mp[i]][1]);
    } return (ret+3)/4;
}
inline bool dfs(int s,int lstp,int lstd) {
    if(h()+s>mxd) return false;
    if(!h()) return true;
    R tmp[10];
    memcpy(tmp,mp,sizeof(mp));
    for(R i=0;i<=3;++i) for(R j=-1;j<=1;j+=2) if(!(i==lstp&&j==-lstd)) {
        change(p[i],j);
        if(dfs(s+1,i,j)) return true;
        memcpy(mp,tmp,sizeof(mp));
    } return false;
}
signed main() { R T=0,Lim; 
    while(1) { register bool flg=true;
        scanf("%s",s); Lim=s[0]^48;
        for(R i=1;i<=9;++i) mp[i]=s[i]^48,flg&=(s[i]==48);
        if(flg) break;
        for(mxd=0;mxd<=Lim&&!dfs(0,-1,0);++mxd) ;    
        printf("%d. %d\n",++T,mxd<=Lim?mxd:-1);
    } 
}

2019.07.13

 
 

转载于:https://www.cnblogs.com/Jackpei/p/11182750.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值