UVALive-6665-Dragons Cruller(BFS+Hash)

题目在此

思路:很经典的搜索。时间比较紧,用map会T。hash函数用了 康托展开。

#include <cstdio>
#include <queue>
#define INF 99999999
using namespace std;

struct S{
int pos,mp[9],step;
bool operator<(const S &p) const
{
    return step>p.step;
}
}t;

int fact[9]={1,1,2,6,24,120,720,5040,40320};//康托展开需要用到

inline int hashval(const int *s)//康托展开
{
    int sum=0;

    for(int i=0;i<9;i++)
    {
        int num=0;

        for(int j=0;j<i;j++) if(s[j]>s[i]) num++;

        sum+=(num*fact[i]);
    }

    return sum;
}

int vis[362800],nxt[4][2]={{0,1},{0,-1},{1,0},{-1,0}};

int main()
{
    int a,b,i,goal[9],key,oldpos,nx,ny;

    while(~scanf("%d%d",&a,&b) && a+b)
    {
        for(i=0;i<9;i++)
        {
            scanf("%d",&t.mp[i]);

            if(!t.mp[i]) t.pos=i;
        }

        for(i=0;i<9;i++) scanf("%d",&goal[i]);

        priority_queue<S>que;

        for(i=0;i<362800;i++) vis[i]=INF;

        t.step=0;

        que.push(t);

        vis[hashval(t.mp)]=0;

        while(!que.empty())
        {
            t=que.top();

            for(i=0;i<9;i++) if(t.mp[i]!=goal[i]) break;

            if(i==9)
            {
                printf("%d\n",t.step);

                break;
            }

            que.pop();

            for(i=0;i<4;i++)
            {
                oldpos=t.pos;

                nx=t.pos/3+nxt[i][0];
                ny=t.pos%3+nxt[i][1];

                if(nx==3) nx=0;
                if(nx==-1) nx=2;
                if(ny==3)
                {
                    ny=0;
                    nx++;
                    if(nx==3) nx=0;
                }
                if(ny==-1)
                {
                    ny=2;
                    nx--;
                    if(nx==-1) nx=2;
                }

                swap(t.mp[nx*3+ny],t.mp[oldpos]);

                if(i<2) t.step+=a;
                else t.step+=b;

                key=hashval(t.mp);

                if(t.step<vis[key])
                {
                    t.pos=nx*3+ny;

                    vis[key]=t.step;

                    que.push(t);
                }

                if(i<2) t.step-=a;
                else t.step-=b;

                swap(t.mp[nx*3+ny],t.mp[oldpos]);

                t.pos=oldpos;
            }
        }
    }
}
时间: 2024-10-07 06:59:48

UVALive-6665-Dragons Cruller(BFS+Hash)的相关文章

UVALive 6665 Dragonas Cruller

题目链接:https://icpcarchive.ecs.baylor.edu/external/66/6665.pdf 题目大意: 有一个3 * 3 的格子: 每个格子上面的数字能够朝上下左右四个方向移动.假设移出范围.则到与其边界上字母相应的还有一边. 例如以下图所看到的: 空白部分分别向上下左右移动之后的情况. 如今.给你左右移动的费用ch,上下移动cv.给你一个初始状态(9个数字,当中0代表该空格为空),一个结束状态,问从初始状态移动到结束状态的最小花费. 解题思路: 事实上这道题想法非

UVALive 6665 Dragon&#226;??s Cruller --BFS,类八数码问题

题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue&g

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

11198 - Dancing Digits(BFS + hash判重)

题目:11198 - Dancing Digits 题目大意:每组数据给出8个数字,可能正可能负.要求最后将这8个数字按照数字绝对值从小到大的排序.排序的规则是让某个数字a邀请另一个数字b跳舞,这样a就可以插到b的左边或是右边,a能邀请b跳舞,则a* b <0 ,且a+b要是素数.题目问给出一组数据问能否通过邀请跳舞来排序,能的话就输出最少的邀请次数,否则输出-1. 解题思路:这题一开始竟然想着dfs,但是后面发现,这样的判断树可以是无限大,因为可以a邀请完b,然后b在邀请a,这样一来一回有可能

POJ 3131 Cubic Eight-Puzzle 双向BFS + HASH

超赞的一道搜索题,麻烦到没朋友,不过思路还是很清楚的. 双向搜索的时候需要注意一个地方就是起始状态只有一个,目标状态最多的时候感觉会有512个,所以要控制两个方向搜索的层数.第一次知道双向搜索还能控制层数,简直点赞. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue&

【BZOJ】1054: [HAOI2008]移动玩具(bfs+hash)

http://www.lydsy.com/JudgeOnline/problem.php?id=1054 一开始我还以为要双向广搜....但是很水的数据,不需要了. 直接bfs+hash判重即可. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using n

UVALive 6665 Dragon’s Cruller (BFS + 优先队列+hash)

题目链接:传送门 题意: 一个九宫格,给定你初始状态和结束状态,每次横向移动和纵向移动都有一定的花费, 问从初始状态到结束状态的最小花费. 分析: BFS,用优先队列维护到达当前状态的最优值,用hash判断当前的状态是否达到过. 代码如下: #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> using nam

BFS+Hash(储存,判重) HDOJ 1067 Gap

题目传送门 题意:一个图按照变成指定的图,问最少操作步数 分析:状态转移简单,主要是在图的存储以及判重问题,原来队列里装二维数组内存也可以,判重用神奇的hash技术 #include <bits/stdc++.h> using namespace std; const int MOD = 1e6 + 7; struct Point { int ch[5][9]; int x[4], y[4]; int step; }; bool vis[MOD]; int ha; int get_hash(i

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

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