IDA*-洛谷P1379 八数码难题

https://daniu.luogu.org/problem/show?pid=1379
省选的收获
暗金
学会了A*啦啦啦;
我在第一天学了A*;
然后回家颓废之余思考思考;
又问了van爷一些小问题;
然后就在fop_zz的 支持 嘲笑下AC了;
A*一开始感觉会很深奥;
然而就是一个剪枝而已;
呵呵呵;
这里又一个估价函数;
当前状态的估价函数是当前在状态理想情况下到达目标状态的代价;
比如我们现在走了g步;
估价为H步;
然后我们迭代加深枚举的k步(k从0开始枚举,所以我们要预先特判无解情况,当然可以掐秒);
如果g+H>k;
显然萎了;
就是这么简单;

至于为什么A*是dfs不是bfs;
因为bfs没有一个确定的k;
而dfs的k我们是枚举的;

至于这样的话有很多的重复;
因为假如答案是4;
那么k=0~3时的搜索是无用的;
但是在这道题目里面显然k不是很大;
而且加入k=ans爆搜的时间复杂度是n;
那么k=0~ans的时间复杂度类似与n*n;
虽然这样,还是比直接暴力好;
那我们可不可以把k-1的所有g==k,g==k-1的状态存下来呢;
好像很麻烦欸;
当然楼k我们可以二分;

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Ll long long
using namespace std;
int fx[9]{0,1,1,1,2,3,3,3,2};
int fy[9]{0,1,2,3,3,3,2,1,1};
int xx[4]{1,-1,0,0};
int yy[4]{0,0,-1,1};
int a[4][4];
int n,m,x,y,z,X,Y,ans;
char c;
int h(){
    int ans=0;
    for(int i=1;i<=3;i++)
    for(int j=1;j<=3;j++)
        if(a[i][j])ans+=abs(i-fx[a[i][j]])+abs(j-fy[a[i][j]]);
    return ans;
}
void dfs(int tf,int X,int Y,int g){
    int H=h();
    if(!H){ans=g;return;}
    if(g==tf||ans||H+g>tf)return;
    for(int i=0;i<4;i++){
        int x=X+xx[i];
        int y=Y+yy[i];
        if(x&&y&&x<4&&y<4){
            swap(a[X][Y],a[x][y]);
            dfs(tf,x,y,g+1);
            swap(a[X][Y],a[x][y]);
        }
    }
}
int main()
{
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
            cin>>c; a[i][j]=c-48;
            if(!a[i][j])X=i,Y=j;
        }
    for(int tf=0;;tf++){
        dfs(tf,X,Y,0);  
        if(ans){printf("%d",ans);return 0;};
    }
}

至于为什么我枚举的变量是tf;
用来纪念我ZJOI2017的颓废;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值