Astar算法

这里主要介绍A*算法的实现:八数码问题 

题目参见:HDU 1043 ,POJ 1077 Eight

#include<stdio.h>
#include<queue>
#include<string>
#include<iostream>
#include<algorithm>

using namespace std;
const int MAXN=1000000;
int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//康拖展开判重
//         0!1!2!3! 4! 5!  6!  7!   8!    9!

bool vis[MAXN];//标记
string path;//记录最终的路径
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};//方向向量
char indexs[5]="udlr";//正向搜索
struct Node
{
    int data[9];
	int f,g,h;
    int loc;//“0”的位置,把“x"当0
    int status;//康拖展开的hash值
    string path;//路径
	bool operator==(const Node &t){
		return status==t.status;
	}
	bool operator<(const Node &t)const{
		return f>t.f;
	}
}start,goal;//起始和终止点

int Cantor(int s[])//康拖展开求该序列的hash值
{
    int sum=0;
    for(int i=0;i<9;i++)
    {
        int num=0;
        for(int j=i+1;j<9;j++)
          if(s[j]<s[i])num++;
        sum+=(num*fac[9-i-1]);
    }
    return sum+1;
}
int ABS(int x){return x<0?(-x):x;}
int Distance(Node suc, Node goal, int i) {//计算方格的错位距离  
	int h1,h2;  //h1表示suc中i所处位置,h2表示goal中i所处的位置
	for(int k = 0; k < 9; k++)  {   
		if(suc.data[k] == i)h1 = k;  
		if(goal.data[k] == i)h2 = k; 
	}  
	return ABS(h1/3 - h2/3) + ABS(h1%3 - h2%3); 
}
int Fvalue(Node suc, Node goal, float speed) {//计算 f 值    
	int h = 0;  
	for(int i = 1; i <= 8; i++)   
		h = h + Distance(suc, goal, i);  
	return h*speed + suc.g; //f = h + g(speed 值增加时搜索过程以找到目标为优先因此可能 不会返回最优解)                                        
} 

bool Astar()
{
    memset(vis,false,sizeof(vis));
    Node cur,next;
    priority_queue<Node> q;
    q.push(start);
    while(!q.empty())
    {
        cur=q.top();
        q.pop();
        if(cur==goal)
        {
            path=cur.path;
            return true;
        }
        int x=cur.loc/3;
        int y=cur.loc%3;
        for(int i=0;i<4;i++)
        {
            int tx=x+dir[i][0];
            int ty=y+dir[i][1];
            if(tx<0||tx>2||ty<0||ty>2)continue;
            next=cur;
            next.loc=tx*3+ty;
            next.data[cur.loc]=next.data[next.loc];
            next.data[next.loc]=0;
            next.status=Cantor(next.data);
			
            if(!vis[next.status])
            {
                vis[next.status]=true;
                next.path=next.path+indexs[i];

                if(next==goal)
                {
                    path=next.path;
                    return true;
                }
				next.g++;//g值
				next.f=Fvalue(next,goal,1);//f值

                q.push(next);
            }
        }
    }
    return false;
}
int main()
{
    freopen("C:\\in.txt","r",stdin);
    char ch;
	//目的节点初始化start
	for(int i=0;i<8;i++)goal.data[i]=i+1;
	goal.data[8]=0;
	goal.status=46234;//123456780对应的康拖展开的hash值
	//end
    while(cin>>ch)
    {
		//起始节点初始化start
        if(ch=='x') {start.data[0]=0;start.loc=0;}
        else start.data[0]=ch-'0';
        for(int i=1;i<9;i++)
        {
            cin>>ch;
            if(ch=='x')
            {
                start.data[i]=0;
                start.loc=i;
            }
            else start.data[i]=ch-'0';
        }
        start.status=Cantor(start.data);//康拖hash值
		start.g=0;
		start.f=Fvalue(start,goal,1);//计算f值
		//end
        if(Astar())
        {
            cout<<path<<endl;
        }
        else cout<<"unsolvable"<<endl;
    }
    return 0;
}


### A*算法介绍 A* (A-star) 算法是一种用于解决最短路径问题的启发式搜索算法,在众多同类算法中最为常用[^1]。该算法不仅能够高效地找到两点之间的最优路径,还因其灵活性而被广泛应用于各种场景下的路径规划。 #### 原理概述 核心在于通过评估函数f(n)=g(n)+h(n),其中n代表当前节点;g(n)是从起点到此节点的实际成本;h(n)则是从这个节点到达目的地的一个估算值(也称为启发式函数)[^2]。为了使计算更加精确并加快收敛速度,通常会选择合适的启发方式来定义h(n)。 #### 数据结构设计 对于每一个可能成为路径一部分的位置都会创建一个`Node`对象表示它,并记录下三个重要属性:位置坐标、累计开销以及预估剩余路程长度。此外还包括指向父级节点的链接以便回溯最终路线图[^4]: ```cpp struct Point { int x, y; Point(int _x, int _y): x(_x), y(_y){} }; struct Node { Point point; double g, h, f; Node *parent; Node(Point pt, double costToStart, double estimatedCostToEnd, Node* prev = nullptr) : point(pt), g(costToStart), h(estimatedCostToEnd), f(g + h), parent(prev) {} }; ``` 这里采用欧氏距离作为两个相邻顶点间边权度量标准之一,即直线上两点间的直线距离。 #### 实现流程 - 初始化开放列表OpenList和关闭列表CloseList为空集; - 将初始状态加入OpenList; - 当OpenList不为空时循环执行以下操作直到找到目标或者无法继续探索为止: - 从未处理过的候选集中选取具有最小f值得元素node_current移至ClosedList; - 对于所有邻接未访问过的新结点new_node, 如果新结点不在OpenList也不在ClosedList,则将其添加入OpenList并将current设为其前驱; 若已经在OpenList里存在相同坐标的旧版本old_version且经由current前往更优(即新的g较小),则更新其前置关系及相应费用。 一旦达到终点或遍历结束仍未发现可行方案,则返回所获得的最佳路径或是报告失败消息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值