洛谷 P1379 八数码难题(A*(BFS+优先队列优化))

题目链接:P1379 八数码难题

题解: 学习A*可以参考这里点这 ,自我评价A*算法是在基础的BFS上引入估值函数的概念,给予BFS中每个点一个类似最短路的距离权值,然后利用优先队列实现对BFS求路径的优化,(就很像是巧妙的基于bfs中点权,再像求最短路中迪杰斯特拉的堆优化一样进行优化),本题中利用距离起点已走步数作为G值,和最终状态的差距作为H值,更加F=H+G用优先队列维护,每次对F较小的先搜索并更新,因为是字符串表示状态,可以用map记录是否访问过和距离起点距离

细节见注释

#include<iostream>
#include<stack>
#include<list>
#include<set>
#include<vector>
#include<algorithm>
#include<math.h>
#include<numeric>
#include<map>
#include<cstring>
#include<queue>
#include<iomanip>
#include<cmath>
#include<queue>
#include <bitset>
#include<unordered_map>/*
	#ifndef local
	#define endl '\n'
#endif */
#define mkp make_pair
using namespace std;
using std::bitset;
typedef long long ll;
typedef long double ld;
const int inf=0x3f3f3f3f;
const ll MAXN=2e6+10;
const ll N=2e5+100;
const ll mod=1e9+7;
const ll hash_p1=1610612741;
const ll hash_p2=805306457;
const ll hash_p3=402653189;
//-----------------------------------------------------------------------------------------------------------------*/
// ll head[MAXN],net[MAXN],to[MAXN],edge[MAXN]/*流量*/,cost[MAXN]//费用;
/* 
void add(ll u,ll v,ll w,ll s){
	to[++cnt]=v;net[cnt]=head[u];edge[cnt]=w;cost[cnt]=s;head[u]=cnt;
	to[++cnt]=u;net[cnt]=head[v];edge[cnt]=0;cost[cnt]=-s;head[v]=cnt;
}
struct elemt{
	int p,v;
};
-----------------------------------
求[1,MAXN]组合式和逆元 
ll mi(ll a,ll b){
	ll res=1;
	while(b){
		if(b%2){
			res=res*a%mod;
		}	
		a=a*a%mod;
		b/=2;
	}
	return res;
}
ll fac[MAXN+10],inv[MAXN+10]
ll C(int m,int n){//组合式C(m,n); 
	if(!n){
		return 1;
	}
	return fac[m]*(inv[n]*inv[m-n]%mod)%mod;
}
fac[0]=1;inv[0]=1;
for(ll i=1;i<=MAXN;i++){
	fac[i]=(fac[i-1]*i)%mod;
	inv[i]=mi(fac[i],mod-2);
}
---------------------------------
 unordered_map<int,int>mp;
//优先队列默认小顶堆 , greater<int> --小顶堆  less<int> --大顶堆  
priority_queue<elemt,vector<elemt>,comp>q;
struct comp{
	public:
		bool operator()(elemt v1,elemt v2){
			return v1.v<v2.v;
		}
};
	set<int>::iterator it=st.begin();
*/
//emplace_back()  等于push_back(),但效率更高,传输pair时emplace_back(i,j)==push_back({i,j}) 
// vector<vector<int>>edge; 二维虚拟储存坐标 
//-----------------------------------------------------------------------------------------------------------------*/
  //map<int,bool>mp[N]; 
  //emplace_back() 
string key="123804765";//目标状态
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
int h(string s){//距离终点的状态差数(粗略的来代表距离终点的距离)
	int res=0;
	for(int i=0;i<9;i++){
		if(s[i]!=key[i]){
			res++;
		}
	}
	return res;
}
struct elemt{
	int g,h;//分别代表距离起点距离,和到达终点所需状态差数量
	string s;//当前状态
	int x,y;//记录0点位置
	bool operator < (const elemt &v)const{//按F=G+H排,优先选F小的,F相同选H小的
		if(g+h==v.g+v.h){
			return h>v.h;
		}
		return g+h>v.g+v.h;
	}
};
priority_queue<elemt>q;//优先队列
map<string,bool>mp;
map<string,int>dis;
int A_STAR(elemt s){
	while(q.size()){
		q.pop();
	}
	q.push(s);
	while(q.size()){
		elemt f=q.top();
		if(f.s==key){//走到了目标状态,返回
			return f.g;
		}
		q.pop();
		int pre=f.x*3+f.y-4;//原0的下标
		for(int i=0;i<4;i++){//四个转换方向
			int fx=f.x+dx[i],fy=f.y+dy[i];
			int tmp=fx*3+fy-4;//换位后0的下标
			if(fx>=1&&fx<=3&&fy>=1&&fy<=3){
				swap(f.s[pre],f.s[tmp]);//更新换位后状态
				if(mp[f.s]==0||mp[f.s]==1&&f.g+1<dis[f.s]){//尝试更新(BFS最短路经典部分)
					dis[f.s]=f.g+1;
					mp[f.s]=1;
					q.push({f.g+1,h(f.s),f.s,fx,fy});
				}
				swap(f.s[pre],f.s[tmp]);//恢复状态
			}
		}
	}
}
int main(){
/*cout<<setiosflags(ios::fixed)<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(不含整数部分)*/
/*cout<<setprecision(8)<<ans<<endl;//输出ans(float)格式控制为8位小数(含整数部分)*/
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);//同步流
	string s;
	cin>>s;
	elemt d;
	d.s=s;
	d.g=0;
	d.h=0;
	for(int i=0;i<9;i++){
		if(s[i]=='0'){
			d.x=i/3+1;
			d.y=i%3+1;
			break;
		}
	}
	cout<<A_STAR(d)<<endl;
	return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值