hihocoder#1312 : 搜索三·启发式搜索(bfs+hash判重)

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

在小Ho的手机上有一款叫做八数码的游戏,小Ho在坐车或者等人的时候经常使用这个游戏来打发时间。

游戏的棋盘被分割成3x3的区域,上面放着标记有1~8八个数字的方形棋子,剩下一个区域为空。

游戏过程中,小Ho只能移动棋子到相邻的空区域上。当小Ho将8个棋子都移动到如下图所示的位置时,游戏就结束了。

小Hi:小Ho,你觉得如果用计算机来玩这个游戏应该怎么做?

小Ho:用计算机来玩么?我觉得应该是搜索吧,让我想一想。

提示:启发式搜索

输入

第1行:1个正整数t,表示数据组数。1≤t≤8。

接下来有t组数据,每组数据有3行,每行3个整数,包含0~8,每个数字只出现一次,其中0表示空位。

输出

第1..t行:每行1个整数,表示该组数据解的步数。若无解输出"No Solution!"

样例输入
3
1 2 3
4 5 6
7 8 0
1 2 3
4 5 6
8 7 0
8 0 1
5 7 4
3 6 2
样例输出
0
No Solution!
25
思路:bfs。9个格子形成一个9位数,用hash链表判重。

#include<bits/stdc++.h>
using namespace std;
const int hashsize=1000007;
int head[hashsize],nex[hashsize],Hash[hashsize],Size;//hash链表
int a[20];//记录状态
struct lenka//记录状态和步数
{
    int sum,step;
};
int n()//把当前状态变为一个9位数
{
    int sum=0;
    for(int i=1;i<=9;i++)sum=sum*10+a[i];
    return sum;
}
int Insert()//插入
{
    int tp=n();
    for(int i=head[tp%hashsize];i!=-1;i=nex[i])if(Hash[i]==tp)return 0;//插入失败
    nex[Size]=head[tp%hashsize];
    head[tp%hashsize]=Size;
    Hash[Size]=tp;
    Size++;
    return 1;
}
void bfs()
{
    Insert();
    queue<lenka>p;
    p.push((lenka){n(),0});
    while(!p.empty())
    {
        lenka now=p.front();p.pop();
        if(now.sum==123456780){printf("%d\n",now.step);return;}//找到答案
        for(int i=9;i>=1;i--,now.sum/=10)a[i]=now.sum%10;
        for(int i=0;i<3;i++)
        {
            for(int j=1;j<=3;j++)
            {
                if(a[i*3+j])continue;
                if(i)//0与上面那个数交换位置
                {
                    swap(a[i*3+j],a[(i-1)*3+j]);
                    if(Insert())p.push((lenka){n(),now.step+1});
                    swap(a[i*3+j],a[(i-1)*3+j]);
                }
                if(i<2)//0与下面那个数交换位置
                {
                    swap(a[i*3+j],a[(i+1)*3+j]);
                    if(Insert())p.push((lenka){n(),now.step+1});
                    swap(a[i*3+j],a[(i+1)*3+j]);
                }
                if(j>1)//0与左边那个数交换位置
                {
                    swap(a[i*3+j],a[i*3+j-1]);
                    if(Insert())p.push((lenka){n(),now.step+1});
                    swap(a[i*3+j],a[i*3+j-1]);
                }
                if(j<3)//0与右边那个数交换位置
                {
                    swap(a[i*3+j],a[i*3+j+1]);
                    if(Insert())p.push((lenka){n(),now.step+1});
                    swap(a[i*3+j],a[i*3+j+1]);
                }
            }
        }
    }
    puts("No Solution!");
}
int main()
{
    int T;cin>>T;
    while(T--)
    {
        for(int i=1;i<=9;i++)scanf("%d",&a[i]);
        memset(head,-1,sizeof head);
        memset(nex,-1,sizeof nex);
        Size=0;
        bfs();
    }
    return 0;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
启发式算法是一种基于经验和直觉的算法,它可以在图论中被广泛应用。下面我将介绍一些具体的应用实例及算法。 1. 最小生成树问题 最小生成树问题是指在一个连通的无向图中,找到一棵生成树,使得所有边的权值之和最小。其中,Kruskal算法和Prim算法是两种常用的启发式算法。 Kruskal算法的基本思想是将所有边按照权值从小到大排序,然后依次加入生成树中,直到生成树中包含了所有的节点。在加入边的过程中,需要判断是否会形成环,如果会形成环,则不加入该边。 Prim算法的基本思想是从一个节点开始,依次加入与该节点相邻的最小权值的边,直到生成树中包含了所有的节点。在加入边的过程中,需要维护一个优先队列,用于选择下一个要加入的边。 2. 最短路径问题 最短路径问题是指在一个加权有向图中,找到从一个节点到另一个节点的最短路径。其中,Dijkstra算法和A*算法是两种常用的启发式算法。 Dijkstra算法的基本思想是从起点开始,依次计算到每个节点的最短路径,直到到达终点。在计算最短路径的过程中,需要维护一个优先队列,用于选择下一个要计算的节点。 A*算法的基本思想是综合考虑启发函数和实际距离,选择下一个要计算的节点。其中,启发函数用于估计从当前节点到终点的距离,实际距离用于计算从起点到当前节点的距离。 3. 最大流问题 最大流问题是指在一个有向图中,找到从源节点到汇节点的最大流量。其中,Ford-Fulkerson算法和Edmonds-Karp算法是两种常用的启发式算法。 Ford-Fulkerson算法的基本思想是不断增加流量,直到无法增加为止。在增加流量的过程中,需要寻找一条增广路径,即从源节点到汇节点的一条路径,使得路径上的边的剩余容量都大于。 Edmonds-Karp算法的基本思想是在Ford-Fulkerson算法的基础上,使用BFS算法寻找增广路径。在BFS算法中,需要将剩余容量大于的边看作是一条边,然后寻找从源节点到汇节点的最短路径。 以上是图论中启发式算法的一些具体应用实例及算法。这些算法在实际应用中具有广泛的应用价值,可以帮助我们解决各种复杂的问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值