luogu1379八数码难题(BFS+Hash判重)

传送门

https://www.luogu.org/problemnew/show/P1379
在这里插入图片描述

思路

  1. 把每一个状态(如123804765)看作一个字符串,然后用Hash得到一个与之对应的数,开个vector存一下
    /* 这里用到的vector用法有1. 遍历for(int i=0,siz=Hash[a].size();i<siz;i++) 2. 插入hash[a].push_back(b); */
  2. 然后用移动0,当作决策进行bfs,发现与目标相同的状态就ok了

Hash

** 单独把这里摘出来,这里用了两个模数,用v当链头,v2当作下标 **

int getHash(int u)
{
    int v=0,v2=0;
    for(int i=1;i<=3;i++)
    for(int j=1;j<=3;j++)
    {
        v=((ll)v*p+a[u][i][j])%mode1;
        v2=((ll)v2*p+a[u][i][j])%mode2;
    }
    if(v==ansv&&v2==ansv2) return 2;
    for(int i=0,size=Hash[v].size();i<size;i++)
        if(Hash[v][i]==v2) return 1;
    Hash[v].push_back(v2);
    return 0;
}

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<vector>
#define ll long long 
using namespace std;
const int inf=0x3f3f3f3f;
const int p=13;
const int mode1=1e6+7;
const int mode2=11229331;
const int N=1e6+10;
int a[N][4][4];
char s[4][4];
int xx[4]={1,0,-1,0};
int yy[4]={0,1,0,-1};
int ansv,ansv2,start_x,start_y;
int x[N],y[N],t[N];
vector <int> Hash[mode1+10];
int getHash(int u)
{
    int v=0,v2=0;
    for(int i=1;i<=3;i++)
    for(int j=1;j<=3;j++)
    {
        v=((ll)v*p+a[u][i][j])%mode1;
        v2=((ll)v2*p+a[u][i][j])%mode2;
    }
    if(v==ansv&&v2==ansv2) return 2;
    for(int i=0,size=Hash[v].size();i<size;i++)
        if(Hash[v][i]==v2) return 1;
    Hash[v].push_back(v2);
    return 0;
}
void bfs()
{
    int v=0,v2=0,head=1,tail=1;
    x[1]=start_x;y[1]=start_y;t[1]=0;
    for(int i=1;i<=3;i++)
    for(int j=1;j<=3;j++)
    {
        v=((ll)v*p+a[1][i][j])%mode1;
        v2=((ll)v2*p+a[1][i][j])%mode2;
    }
    if(v==ansv&&v2==ansv2) {cout<<"0"<<endl;return ;}
    while(head<=tail)
    {
        int nx=x[head],ny=y[head],nt=t[head];
        for(int i=0;i<4;i++)
        {
            int cx=nx+xx[i],cy=ny+yy[i];
            if(cx>0&&cx<4&&cy>0&&cy<4)
            {
                swap(a[head][nx][ny],a[head][cx][cy]);
                int q=getHash(head);
                if(q==2){cout<<nt+1<<endl;return ;}
                else if(q==1){swap(a[head][nx][ny],a[head][cx][cy]);continue;}
                else
                {
                    tail++;
                    x[tail]=cx;
                    y[tail]=cy;
                    t[tail]=nt+1;
                    for(int i=1;i<=3;i++)
                    for(int j=1;j<=3;j++)
                    a[tail][i][j]=a[head][i][j];
                    swap(a[head][nx][ny],a[head][cx][cy]);
                }
                
            }
        }
        head++;
    }
}
int main()
{
    a[0][1][1]=1;a[0][1][2]=2;a[0][1][3]=3;
    a[0][2][1]=8;a[0][2][2]=0;a[0][2][3]=4;
    a[0][3][1]=7;a[0][3][2]=6;a[0][3][3]=5;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
        {
            ansv=((ll)ansv*p+a[0][i][j])%mode1;
            ansv2=((ll)ansv2*p+a[0][i][j])%mode2;
        }
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=3;j++)
        {
            cin>>s[i][j];
            a[1][i][j]=s[i][j]-'0';
            if(a[1][i][j]==0)
            {
                start_x=i;
                start_y=j;
            }
        }
    }
    bfs();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值