hdu1067-Gap(bfs+哈希)

Let‘s play a card game called Gap. You have 28 cards labeled with two-digit numbers. The first digit (from 1 to 4) represents the suit of the card, and the second digit (from 1 to 7) represents the value of the card.
First, you shu2e the cards and lay them face up on the table in four rows of seven cards, leaving a space of one card at the extreme left of each row. The following shows an example of initial layout.

Next, you remove all cards of value 1, and put them in the open space at the left end of the rows: "11" to the top row, "21" to the next, and so on.
Now you have 28 cards and four spaces, called gaps, in four rows and eight columns. You start moving cards from this layout.

At each move, you choose one of the four gaps and fill it with the successor of the left neighbor of the gap. The successor of a card is the next card in the same suit, when it exists. For instance the successor of "42" is "43", and "27" has no successor.
In the above layout, you can move "43" to the gap at the right of "42", or "36" to the gap at the right of "35". If you move "43", a new gap is generated to the right of "16". You cannot move any card to the right of a card of value 7, nor to the right of a gap.
The goal of the game is, by choosing clever moves, to make four ascending sequences of the same suit, as follows.

Your task is to find the minimum number of moves to reach the goal layout.

Input

The input starts with a line containing the number of initial layouts that follow.
Each layout consists of five lines - a blank line and four lines which represent initial layouts of four rows. Each row has seven two-digit numbers which correspond to the cards.

Output

For each initial layout, produce a line with the minimum number of moves to reach the goal layout. Note that this number should not include the initial four moves of the cards of value 1. If there is no move sequence from the initial layout to the goal layout, produce "-1".

Sample Input

4

12 13 14 15 16 17 21

22 23 24 25 26 27 31

32 33 34 35 36 37 41

42 43 44 45 46 47 11

26 31 13 44 21 24 42

17 45 23 25 41 36 11

46 34 14 12 37 32 47

16 43 27 35 22 33 15

17 12 16 13 15 14 11

27 22 26 23 25 24 21

37 32 36 33 35 34 31

47 42 46 43 45 44 41

27 14 22 35 32 46 33

13 17 36 24 44 21 15

43 16 45 47 23 11 26

25 37 41 34 42 12 31

Sample Output

0

33

60

-1

题意:给出表如第一个图,给出每个数,共有28个数,首先要将11,21,31,41放到前面去如第二个图,然后每次可以挑选一个空位把某个数放在此位置,但是

要保证此数恰好是空位左边的数的后一个数,比如空位左边的数是42,则只能把43移到空位去。如果是47的话是没有后一个数的。

解析:总共有32个数,用哈希保存状态。然后bfs即可。详见代码实现。

代码

#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
int eps=0.0000001;
typedef
__int64 LL;
const
LL mod=1000007;
int
maze[4][8];
LL Hash[mod];
LL base[32];
struct
node
{

    int
px[4],py[4]; //保存四个空位
    int S[4][8];     //整个图
    int dist;
}
Nod[100005];
int
id;
queue<int> que;

int goal[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 }
};

LL G;
void
GetBase()  //打出2^i
{
    base[0]=1;
    for
(int i=1;i<32;i++) base[i]=base[i-1]*2;
}

int
GetId(int x,int y){ return x*8+y; }
void
SetHead()
{

    for
(int i=0;i<4;i++)
        for
(int j=1;j<8;j++)
    {

        int
a=maze[i][j]/10;   
        int
b=maze[i][j]%10;
        if
(b==1) { maze[a-1][0]=maze[i][j]; maze[i][j]=0; } //把11,21,31,41挑出来
    }
}

LL GetHash(int S[4][8])
{

    LL ret=0;
    for
(int i=0;i<4;i++)
        for
(int j=0;j<8;j++) ret+=(LL)S[i][j]*base[GetId(i,j)];  //得到哈希值
    return ret;
}

bool
InsertHash(LL val)
{

   LL v=val%mod;
   while
(Hash[v]!=-1&&Hash[v]!=val)  v=(v+10)%mod;   //判重
   if(Hash[v]==-1){ Hash[v]=val; return true; }  //可以插入
   return false;
}

void
init()
{

    memset(Hash,-1,sizeof(Hash));
    while
(!que.empty())  que.pop();
    id=0;
    G=GetHash(goal);
    int
k=0;
    int
cur=id++;
    for
(int i=0;i<4;i++)
        for
(int j=0;j<8;j++)
    {

        Nod[cur].S[i][j]=maze[i][j];
        if
(maze[i][j]==0){ Nod[cur].px[k]=i; Nod[cur].py[k++]=j; }  //得到最初的状态
    }
    Nod[cur].dist=0;
    que.push(cur);
}

void
Change_S(node& e,int x,int y,int pick,int k)
{

    for
(int i=0;i<4;i++)
        for
(int j=0;j<8;j++)
        if
(e.S[i][j]==pick)
    {

        e.S[i][j]=0;
        e.S[x][y]=pick;
        e.px[k]=i; e.py[k]=j;
        return
;
    }
}

void
AddNode(int now)
{

    node& e=Nod[now];
    for
(int i=0;i<4;i++)
    {

        int
x=e.px[i];
        int
y=e.py[i];
        int
pre=e.S[x][y-1];
        if
(pre==0) continue;  //也是空位不管

        int
a=pre/10;
        int
b=pre%10;
        if
(b==7) continue;  //不能是*7

        int
pick=pre+1;
        node t=e;
        t.dist++;
        Change_S(t,x,y,pick,i);
        LL nowG=GetHash(t.S);
        if
(!InsertHash(nowG)) continue;  //能否插入

        int
cur=id++;
        Nod[cur]=t;
        que.push(cur);
    }
}

int
solve()
{

    SetHead();
    init();
    while
(!que.empty())
    {

        int
now=que.front();  que.pop();
        node& e=Nod[now];
        LL nowG=GetHash(e.S);
        if
(nowG==G) return e.dist;  //找到解
        AddNode(now);
    }

    return
-1;
}

int
main()
{

    int
T;
    GetBase();
    cin>>T;
    while
(T--)
    {

        memset(maze,0,sizeof(maze));
        for
(int i=0;i<4;i++)
            for
(int j=1;j<8;j++) cin>>maze[i][j];
        printf("%d\n",solve());
    }

    return
0;
}

时间: 2024-10-08 00:32:13

hdu1067-Gap(bfs+哈希)的相关文章

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

HDU1067 Gap 【BFS+MAP】

Gap Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 597    Accepted Submission(s): 327 Problem Description Let's play a card game called Gap. You have 28 cards labeled with two-digit numbers.

HDU1067 Gap( BFS+ HASH 剪枝,矩阵用一个数表示)

题意:在4*8 的图中,给你4种类型的牌,每种牌序号1-7,比如42表示第4种牌的第二张,现在给你4*7一共28张,同时最左边的一列开始空的,第一步你要做的是把每种类型的1号牌从上到下放在这列空的位置上,然后在新出现的空位置,你要挑选空位子左边的那张牌的后继,如果没有的话,就不能操作. 解法:题目的状态很多,还有要怎么表示一个状态已经搜索过了呢.那就把矩阵做一下转化,把当前矩阵按行展开,以2为基数化为十进制的数(最大2^32,所以用Long Long),接下来存储这些整数,用map,set应该也

【算法】BFS+哈希解决八数码问题

15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖"X"; 拼图的目的是安排瓷砖以便它们排序为: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15× 这里唯一合法经营是交流'X'与它共享一个边缘的瓷砖之一.作为一个例子,举动下列顺序解决了一个稍微加扰难题: 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 5 6 7 8 5 6

HDU 1067 Gap BFS+Hash

感觉可以用bfs暴力,一开始写了一个很暴力的bfs,hash判重,本地跑了几组数据发现至少要2s才能过,交上去估计要TLE,试探性的交了一发1A了,原来时限是10s,我看成1s了,真是逗逼...还一直不敢写 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include &

codevs1004四子连棋[BFS 哈希]

1004 四子连棋  时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局. ● ○ ●   ○ ● ○ ● ● ○ ● ○ ○ ● ○   输入描述 Inpu

BFS学习总结

BFS学习总结 给你一个n*m的网格迷宫,迷宫中有些格子不能走,其他的格子都能走.然后给你起点与终点,问你从起点走到终点最少需要多少步? 上面的问题就是一个典型的BFS问题,对于这类问题来说,只要你掌握了这类问题的关键思想,其实他们都是可以用类似的思路来做的. 你可以把BFS问题想象成:从一个父亲(起点状态)生儿子(后继状态),儿子又生孙子(后继状态)的过程,只要这个家族中出生了一个满意的后代(终点状态),这个家族就不生了. 但是如果这个家族中有两个完全一样的人出生(他们的辈分不一定相同),那么

【CodeVS1225】八数码难题

Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. Input 输入初试状态,一行九个数字,空格用0表示 Output 只有一

leetcode解题目录

参考文献:http://blog.csdn.net/lanxu_yy/article/details/17848219 不过本文准备用超链接的方式连接到相应解答页面,不断更新中 题目 算法 数据结构 注意事项 Clone Graph BFS 哈希表 Word Ladder II BFS 哈希表 Surrounded Regions BFS 矩阵 Word Ladder BFS N/A Binary Tree Level Order Traversal BFS|前序遍历 队列 Binary Tre