#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<unordered_map>
using namespace std;
const int N=6;
int n;//不知道有几个规则,所以直接输入来判断有几个规则
string A,B;
string a[N],b[N];
int extend(queue<string>& q, unordered_map<string,int>& da, unordered_map<string,int>& db,
string a[],string b[])
{
int d=da[q.front()];
while(q.size()&&da[q.front()]==d)
{
auto t=q.front();
q.pop();
for(int i=0;i<n;i++)
{
for(int j=0;j<t.size();j++)
{
if(t.substr(j,a[i].size())==a[i])
{
string r=t.substr(0,j)+b[i]+t.substr(j+a[i].size());
if(db.count(r)) return da[t]+db[r]+1;
if(da.count(r)) continue;
da[r]=da[t]+1;
q.push(r);
}
}
}
}
return 11;
}
int bfs()
{
if(A==B) return 0;
queue<string>qa,qb;//定义一个队列
unordered_map<string,int> da,db;
qa.push(A),qb.push(B);
da[A]=db[B]=0;
int step=0;//定义一个步数
while(qa.size()&&qb.size())
{
int t;
if(qa.size()<qb.size()) t=extend(qa,da,db,a,b);//从队列长度较小的那一边进行扩展
else t=extend(qb,db,da,b,a);//用a替换b;
if(t<=10) return t;
if(++step==10) return -1;
}
return -1;
}
int main()
{
cin>>A>>B;
while(cin>>a[n]>>b[n]) n++;
int t=bfs();
if(t==-1) puts("NO ANSWER!");
else cout<<t<<endl;
return 0;
}
A*算法---从起点到终点的最短距离(启发函数)适用于数据范围较大
估价函数要>=0并且要小于真实值
基本步骤:(有点像dijkstra(形式上))
dijkstra可看作所有估价为0的A*算法
1.首先将bfs中的队列都换成优先队列
2.while(!q.empty())
{
t<-优先队列的对头(小根堆)
除了存真实距离值外(从起点到当前点的真实距离)
还要存一个估计距离(从终点到当前点的估计距离)
每次挑一个预测距离+真实距离最短的点扩展
for t的所有邻边
将邻边入队
}
需满足条件---估计的距离<=真实距离(从当前点到终点)
保证当终点出队时是最小值(但是不保证中间的某个点出队时是最小值)
1.BFS 在入队时判重
2.dijkstra 在出队时判重
3.A* 不能判重
AcWing 179. 八数码(使用A*算法)
//估价函数:
//当前状态中每个数与它目标位置的曼哈顿距离之和
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
int f(string state)
{
int res = 0;
for (int i = 0; i < state.size(); i ++ )
if (state[i] != 'x')
{
int t = state[i] - '1';
res += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
}
return res;
}
string bfs(string start)
{
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
char op[4] = {'u', 'r', 'd', 'l'};
string end = "12345678x";
unordered_map<string, int> dist;
unordered_map<string, pair<string, char>> prev;
priority_queue<pair<int, string>, vector<pair<int, string>>, greater<pair<int, string>>> heap;
heap.push({f(start), start});
dist[start] = 0;
while (heap.size())
{
auto t = heap.top();
heap.pop();
string state = t.second;
if (state == end) break;
int step = dist[state];
int x, y;
for (int i = 0; i < state.size(); i ++ )
if (state[i] == 'x')
{
x = i / 3, y = i % 3;
break;
}
string source = state;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < 3 && b >= 0 && b < 3)
{
swap(state[x * 3 + y], state[a * 3 + b]);
if (!dist.count(state) || dist[state] > step + 1)
{
dist[state] = step + 1;
prev[state] = {source, op[i]};
heap.push({dist[state] + f(state), state});
}
swap(state[x * 3 + y], state[a * 3 + b]);
}
}
}
string res;
while (end != start)
{
res += prev[end].second;
end = prev[end].first;
}
reverse(res.begin(), res.end());
return res;
}
int main()
{
string g, c, seq;
while (cin >> c)
{
g += c;
if (c != "x") seq += c;
}
int t = 0;
for (int i = 0; i < seq.size(); i ++ )
for (int j = i + 1; j < seq.size(); j ++ )
if (seq[i] > seq[j])
t ++ ;
if (t % 2) puts("unsolvable");
else cout << bfs(g) << endl;
return 0;
}
使用朴素算法
#include <iostream>
#include <algorithm>
#include <queue>
#include <unordered_map>
using namespace std;
int bfs(string start)
{
//定义目标状态
string end = "12345678x";
//定义队列和dist数组
queue<string> q;
unordered_map<string, int> d;
//初始化队列和dist数组
q.push(start);
d[start] = 0;
//转移方式
int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
while(q.size())
{
auto t = q.front();
q.pop();
//记录当前状态的距离,如果是最终状态则返回距离
int distance = d[t];
if(t == end) return distance;
//查询x在字符串中的下标,然后转换为在矩阵中的坐标
int k = t.find('x');
int x = k / 3, y = k % 3;
for(int i = 0; i < 4; i++)
{
//求转移后x的坐标
int a = x + dx[i], b = y + dy[i];
//当前坐标没有越界
if(a >= 0 && a < 3 && b >= 0 && b < 3)
{
//转移x
swap(t[k], t[a * 3 + b]);
//如果当前状态是第一次遍历,记录距离,入队
if(!d.count(t))
{
d[t] = distance + 1;
q.push(t);
}
//还原状态,为下一种转换情况做准备
swap(t[k], t[a * 3 + b]);
}
}
}
//无法转换到目标状态,返回-1
return -1;
}
int main()
{
string c, start;
//输入起始状态
for(int i = 0; i < 9; i++)
{
cin >> c;
start += c;
}
cout << bfs(start) << endl;
return 0;
}
AcWing 178. 第K短路(待更新~)