hdu3095-Eleven puzzle(双向搜索+哈希)

Partychen invents a new game named “Eleven Puzzle” .Just like the classic game “Eight Puzzle”,but there some difference between them:The shape of the board is different and there are two empty tiles. 

The tile in black means it’s empty

Each step you can move only one tile. 
Here comes the problem.How many steps at least it required to done the game.

Input

The first line of input contains one integer specifying the number of test cases to follow. 
Every case contains five lines to describe the initial status of the board. 0 means empty.

It’s confirmed that the board is legal.

Output

Output one line for each testcase.Contain an integer denotes the minimum step(s) it need to complete the game.Or “No solution!” if it’s impossible to complete the game within 20 steps.

Sample Input

3

2

1 0 3

4 5 6 7 8

9 0 11

10

0

1 2 3

4 5 6 7 8

9 10 11

0

0

11 10 9

8 7 6 5 4

3 2 1

0

Sample Output

2

0

No solution!

题意:给出上图的11数码,有2个空格,每次可以移一步,问能否在20步以内达到目标状态,如果能输出步数,否则输出No solution!

解析:题目给了20步的限制,而且前后搜效果是一样的,所以很容易想到双向bfs,但是状态怎么保存呢,有11个数外加2个空格,可以考虑用康拓展开,但不能用数组保存值,因为值太大了,所以可以考虑用map,我用的方法是哈希,给每个数乘上一个权值,然后加起来哈希成一个值,用数组模拟链表保存状态,但可能出现两种不同的状态哈希成同一个值,所以在相同的情况下还要整个进行对比。

源代码

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<utility>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<iterator>
#include<stack>
using namespace std;
const int INF=1e9+7;
const double eps=1e-7;
const int mod=1000007;
const int maxn=100005;
int f[2],r[2];   //双向bfs的两个队列的队首队尾指针
int dx[]={-1,0,1,0},dy[]={0,-1,0,1}; //方向数组
bool in(int x,int y){ return x>=0&&x<5&&y>=0&&y<5; } //是否越界
struct node
{
    int px[2],py[2];  //保存2个空格的位置和整个数组
    int A[5][5];
}nod[2][maxn];  //0是前面搜,1是后面搜
int B[5][5]={   //最终状态
    -1,-1,0,-1,-1,
    -1,1,2,3,-1,
    4,5,6,7,8,
    -1,9,10,11,-1,
    -1,-1,0,-1,-1
};
bool Same(int A[][5])  //判断该状态是否与最终的状态相等
{
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
        if(A[i][j]!=B[i][j]) return false;
    return true;
}
int F[20];  //保存2^i
void GetF()
{
    F[0]=1;
    for(int i=1;i<15;i++) F[i]=F[i-1]*2;
}
int Get(int A[][5])  //得到哈希值
{
    int ret=0,k=0;
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++) if(A[i][j]>0) ret+=F[k++]*A[i][j]; //乘上一个权值
    return ret;
}
struct Hash
{
    int v,next,nid,k;   //是哈希值,next指向下一个节点,nid和k分别保存是下标和0或1
}ha[mod+maxn];
int hash_id;
bool check(int a,int k1,int b,int k2)  //判断是否完全相等
{
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
        if(nod[k1][a].A[i][j]!=nod[k2][b].A[i][j]) return false;
    return true;
}
int Insert_Hash(int v,int nid,int k)  //插入
{
    int a=v%mod;
    int p=ha[a].next;
    while(p!=-1)
    {
        if(ha[p].v==v&&check(ha[p].nid,ha[p].k,nid,k)) return ha[p].k;//有相同的状态
        p=ha[p].next;
    }
    p=++hash_id;  //没有则增加新节点,前插法
    ha[p].v=v; ha[p].nid=nid; ha[p].k=k;
    ha[p].next=ha[a].next; ha[a].next=p;
    return -1;   //-1代表插入了新节点
}
bool AddNode(node& t,int i,int j,int k)
{
    int x=t.px[i],y=t.py[i];
    int nx=x+dx[j],ny=y+dy[j];
    if(!in(nx,ny)||t.A[nx][ny]<=0) return false;
    node& tt=nod[k][r[k]];
    tt=t;
    swap(tt.A[x][y],tt.A[nx][ny]);  //交换
    tt.px[i]=nx; tt.py[i]=ny;
    int a=Insert_Hash(Get(tt.A),r[k],k);
    if(a==-1){ r[k]++; return false; } //队尾指加1
    else if(a==k) return false;   //自己原来访问过的状态
    else return true;    //相遇了,找到了解
}
void Print(node& t)
{
    for(int i=0;i<5;i++)
    {
        for(int j=0;j<5;j++) printf("%d ",t.A[i][j]);
        puts("");
    }
    puts("=========");
    getchar();
}
bool bfs(int k)
{
    int& be=f[k];
    int en=r[k];
    while(be<en)
    {
        node& t=nod[k][be++];
        //Print(t);
        for(int i=0;i<2;i++)
            for(int j=0;j<4;j++) if(AddNode(t,i,j,k)) return true;
    }
    return false;
}
int solve()
{
    if(Same(nod[0][0].A)) return 0;
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++) nod[1][0].A[i][j]=B[i][j];  //最终状态
    nod[1][0].px[0]=0; nod[1][0].py[0]=2;
    nod[1][0].px[1]=4; nod[1][0].py[1]=2;
    int step=0;
    f[0]=f[1]=0,r[0]=r[1]=1;
    for(int i=0;i<mod;i++) ha[i].next=-1;
    hash_id=mod-1;
    while(f[0]<r[0]||f[1]<r[1]) //双向搜
    {
        step++;
        if(bfs(0)) return step;
        step++;
        if(bfs(1)) return step;
        if(step>=20) return -1;
    }
    return -1;
}
int main()
{
    int T;
    GetF();
    scanf("%d",&T);
    while(T--)
    {
        int k=0;
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)//得到初始状态
        {
            if(B[i][j]==-1) { nod[0][0].A[i][j]=-1; continue; }
            scanf("%d",&nod[0][0].A[i][j]);
            if(nod[0][0].A[i][j]==0)
                { nod[0][0].px[k]=i; nod[0][0].py[k++]=j; }
        }
        int ans=solve();
        if(ans==-1) printf("No solution!\n");
        else printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-01 19:55:50

hdu3095-Eleven puzzle(双向搜索+哈希)的相关文章

WUST暑假集训第一周简单小结

目录 一.dfs序在树状图中的经典应用 二.初探双向广度优先搜索 三.整体二分思想完美解决kth number问题 四.实战模拟退火思想(变步长贪心算法) 五.凸包问题经典例题 六.树的重心问题经典例题 七.矩阵快速幂例题 一.dfs序在树状图中的经典应用 首先是dfs序的问题,什么是dfs序? 我的理解:dfs序也就是将一棵树通过树的遍历顺序将一棵树转化为父节点包含了子节点的序列,n个结点的树对应n个数的序列,一个结点在序列中的表现形式为一段区间,这段区间中包含了该结点的子树区间,且构造的区间

Aizu 0121 Seven Puzzle (康托展开+bfs)

Seven Puzzle Time Limit : 1 sec, Memory Limit : 65536 KB 7パズルは8つの正方形のカードとこれらのカードがぴたりと収まる枠を使って行います.それぞれのカードは互いに区別できるように.0,1,2....7と番号がつけられています.枠には.縦に2個.横に4個のカードを並べることができます. 7パズルを始めるときには.まず枠にすべてのカードを入れます.枠のなかで0のカードだけは.上下左右に隣接するカードと位置を交換することができます.たとえば.枠

poj1200Crazy Search (哈希)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Crazy Search Time Limit: 1000MS   Memory Limit: 65536K Description Many people like to solve hard puzzles some of which may lead them to madness. One such puzzle could be finding a hidden pri

POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)

Description Let's play a puzzle using eight cubes placed on a 3 × 3 board leaving one empty square. Faces of cubes are painted with three colors. As a puzzle step, you can roll one of the cubes to a adjacent empty square. Your goal is to make the spe

NYOJ 2356: 哈希计划【模拟】

题目描述 众所周知,LLM的算法之所以菜,就是因为成天打游戏,最近LLM突然想玩<金庸群侠传X>,结果进去后各种被虐,LLM就开始研究这个游戏的代码,顺便还学会了一点点点点lua语言,然后就开始了伟大的改游戏代码之旅,然后LLM发现自己too young了,这个游戏把所有的文本都进行了哈希,如果自己改了代码或者剧情文本的话它哈希出来的值就会和原来的哈希值不一样......然后游戏就会打不开.....,现在LLM发现了文本的哈希函数,要求你写个程序,功能为: 输入一段字符串,输出一个哈希值 为了

7.哈希

哈希(Hash)又称散列,它是一个很常见的算法.在Java的HashMap数据结构中主要就利用了哈希.哈希算法包括了哈希函数和哈希表两部分.我们数组的特性可以知道,可以通过下标快速(O(1))的定位元素,同理在哈希表中我们可以通过键(哈希值)快速的定位某个值,这个哈希值的计算就是通过哈希函数(hash(key) = address )计算得出的.通过哈希值即能定位元素[address] = value,原理同数组类似. 最好的哈希函数当然是每个key值都能计算出唯一的哈希值,但往往可能存在不同的

哈希表

哈希表支持的一种最有效的检索方法:散列. 由于计算哈希值和在数组中进行索引都只消耗固定时间,因此哈希表的最大亮点在于他是一种运行时间在常量级的检索方法. 哈希表主要有两种: 1.链式哈希表:将数据存储在桶中的哈希表,每个桶里面都是一个链表,且链表的容量随着冲突的增大而增大.(换句话说就是如果有冲突,会在桶中的链表加上一个存储的值) 2.开地址哈希表:将数据存在表本身,而不是在桶中,他通过各种探查方法来避免冲突. 解决冲突: 不管在以上那种哈希表中,我们的目标是尽可能均匀的分配表中的元素.所以我们

Aizu 2784 Similarity of Subtrees(树哈希)

Similarity of Subtrees Define the depth of a node in a rooted tree by applying the following rules recursively: The depth of a root node is 0. The depths of child nodes whose parents are with depth d are d+1 . Let S(T,d) be the number of nodes of T w

8. 蛤蟆的数据结构进阶八哈希表相关概念

8. 蛤蟆的数据结构进阶八哈希表相关概念 本篇名言:"作家当然必须挣钱才能生活,写作,但是他决不应该为了挣钱而生活,写作.--马克思" 前些笔记我们学习了二叉树相关.现在我们来看下哈希表.这篇先来看下哈希表的相关概念 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47347273 1.  哈希表的概念 哈希表(HashTable)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构.它通过把关键