hdu 1067 && poj 2046 Gap (bfs+hash)

题意:初始状态为左边空一行,然后数字在右边28个格子。末态要求按一副卡片在一行顺序排,

            即第一行为11-17,第二行21-27,。。。。

            可以通过四个空格来转移卡片,问从初始状态到末态最少要多少步。


思路:

1、状态太多了,需要用hash记录状态。

2、bfs


hash函数的设计:

【1】 h += (t[i][j]*base[i*8+j]); 将整个盘的状态用此值表示。它的位置就是h=hash%M;

【2】 用的是再哈希法hash =(v+10)%M来处理冲突。


总结:aim计算出来的值很大,tag常数后要加LL。

            该用long long 的地方要用long long

#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#define M 1000007

using namespace std;

long long tag;
long long base[33]={1};
long long hash[M];
bool flag;

struct djw
{
    int bx[4],by[4];
    int map[4][8];
    long long step;
}w;

queue<djw> q;
int aim[4][8]=
{
    11,12,13,14,15,16,17,0,
    21,22,23,24,25,26,27,0,
    31,32,33,34,35,36,37,0,
    41,42,43,44,45,46,47,0
};

long long gethash(int t[][8])
{
    long long h=0;
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<8;j++)
        {
            h += t[i][j]*base[i*8+j];
        }
    }
    if(h==tag) flag=true;
    return h;
}

bool insert(long long valve)
{
    long long v = valve%M;
    while(hash[v]!=-1 && hash[v]!=valve)
    {
        v = (v+10)%M;
    }
    if(hash[v]==-1)
    {
        hash[v]=valve;
        return true;
    }
    return false;
}

bool work(int t[][8])
{
    long long fuck = gethash(t);
    return insert(fuck);
}

int bfs()
{
    djw cur,next;
    while(!q.empty())
    {
        cur = q.front();
        q.pop();
        for(int k=0;k<4;k++)
        {
            next = cur;
            int xx=next.bx[k];
            int yy=next.by[k];
            for(int i=0;i<4;i++)
            {
                for(int j=0;j<8;j++)
                {
                    if(next.map[i][j]==0) continue;
                    if(next.map[i][j]!=next.map[xx][yy-1]+1) continue;
                    swap(next.map[i][j],next.map[xx][yy]);
                    if(work(next.map))
                    {
                        next.bx[k]=i;
                        next.by[k]=j;
                        next.step = cur.step+1;
                        q.push(next);
                        if(flag) return next.step;
                    }
                }
            }
        }
    }
    return -1;
}

int main()
{
    int T;
    for(int i=1;i<33;i++)
    {
        base[i]=base[i-1]*2;
    }
    tag=98430874871LL;
    scanf("%d",&T);
    while(T--)
    {
        while(!q.empty()) q.pop();
        flag=false;
        int k=0;
        memset(hash,-1,sizeof(hash));
        w.map[0][0]=w.map[1][0]=w.map[2][0]=w.map[3][0]=0;
        for(int i=0;i<4;i++)
        {
            for(int j=1;j<8;j++)
            {
                scanf("%d",&w.map[i][j]);
                if(w.map[i][j]==11) {swap(w.map[i][j],w.map[0][0]);w.bx[k]=i;w.by[k++]=j;}
                else if(w.map[i][j]==21) {swap(w.map[i][j],w.map[1][0]);w.bx[k]=i;w.by[k++]=j;}
                else if(w.map[i][j]==31) {swap(w.map[i][j],w.map[2][0]);w.bx[k]=i;w.by[k++]=j;}
                else if(w.map[i][j]==41) {swap(w.map[i][j],w.map[3][0]);w.bx[k]=i;w.by[k++]=j;}
            }
        }
        w.step=0;
        work(w.map);
        q.push(w);
        if(flag) printf("0\n");
        else printf("%d\n",bfs());
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值