P5507机关-题解

这是道很好的搜索练手题
可以用广为人知的搜索三巨头求解

  • 双向搜索
  • IDA* (在这题貌似被禁了
  • A*

这篇题解主要介绍用 A_star 算法 AC 这道题

1. 思路

结构体 记录 路径 状态
以及实际步数 g(n) 和估价步数 h(n)
我们都知道 A* 算法的核心在于其估价函数 h(n)
每次取出对应 g(n) + h(n) 最小的 进行下一步搜素

引出一个疑惑 :
每改变一个机关的状态都会有另一个机关跟着改变
那么估价函数如何求解 ?
看作是两个一起变换
可以 用当前状态距离目标状态的理想差值除去 2 得到

2.解法

使用优先队列存储结构体
所以我们需要 重载运算符

bool operator<(const node &a,const node &b){
	return a.g+a.h>b.g+b.h;
}

经检验 :
由于看作两个机关同时向着目标前进 过于理想
此题的估价函数可以稍微调高一些,用于优化时间复杂度
参数为原估价函数的 1.3
但此时的时间复杂度仍高了些
所以最后加上 map 去重 即可

3. Code

#include<bits/stdc++.h>
using namespace std;
struct node{
	string state;//状态 
	string path;//路径 
	int g;//实际步数 
	int h;//估价函数 
};
map<string,bool> mark;
//重载运算符 
bool operator<(const node &a,const node &b){
	return a.g+a.h>b.g+b.h;
}
priority_queue<node> q;
//估价函数 
int eva(string s){
    int cnt=0;
    for(int i=1;i<=12;i++)
        if(s[i]!='1') cnt+=5-(int)(s[i]-48);
    return cnt/2*1.3;
}
void print(node s){
	printf("%d\n",s.g);
	for(int i=0;i<s.path.size();i++) cout<<(int)(s.path[i]-48)<<" ";
}
int main(){ 
	int gear[13][5];//机关触发机制 
	node start;
	start.state+=(char)(48);
	for(int i=1;i<=12;i++)
		for(int j=1;j<=5;j++){
			int x;scanf("%d",&x);
			if(j==1) start.state+=(char)(x+48);
			else gear[i][j-1]=x;
		}
	start.g=0;
	start.h=eva(start.state);
	if(!start.h){printf("0");return 0;}
	mark[start.state]=true;
	q.push(start);
	while(!q.empty()){
		node a=q.top();q.pop();
		for(int i=1;i<=12;i++){
			//触发机关 
			int x=(int)(a.state[i]-48);//x为i机关的状态 
			int j=gear[i][x];//j为i机关的连锁机关 
			int y=(int)(a.state[j]-48);//y为j机关的状态
			//改变状态 
			if(x==4) x=1;
			else x+=1;
			if(y==4) y=1;
			else y+=1;
			 
			node s;//转换入队列 
			s.state+=(char)(48);
			for(int u=1;u<=12;u++){
				if(u==i){s.state+=(char)(x+48);continue;}
				if(u==j){s.state+=(char)(y+48);continue;}
				s.state+=a.state[u];
			}
			
			if(!mark[s.state]){//map去重 
				s.g=a.g+1;
				s.h=eva(s.state);
				mark[s.state]=true;
				s.path=a.path+(char)(i+48);
				if(!s.h){print(s);return 0;}
				q.push(s);
			}
		}
	}
	return 0;
} 
posted @ 2022-06-06 16:59  ThinkGone  阅读(67)  评论(0编辑  收藏  举报