1 专题说明
本专题用来记录使用双向广搜BFS和A星算法求解的题目。
2 训练
题目1:190字串变换
考点:从起点开始搜,从终点开始搜,即双向广搜。
C++代码如下,
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <unordered_map>
#include <string>
using namespace std;
string start_node, end_node;
vector<pair<string,string>> map_subsrc_subdst;
unordered_map<string, int> dist1; //从起点出发的距离
unordered_map<string, int> dist2; //从终点出发的距离
int main() {
cin >> start_node >> end_node;
string a, b;
while (cin >> a >> b) {
map_subsrc_subdst.emplace_back(a,b); //a->b,注意a并不是唯一的,存在一对多的情况。
}
queue<string> q1;
q1.push(start_node);
dist1[start_node] = 0;
queue<string> q2;
q2.push(end_node);
dist2[end_node] = 0;
int res = -1;
while (!q1.empty() && !q2.empty()) {
//先扩展哪一个,扩展数量少的那个
if (q1.size() < q2.size()) {
//扩展q1
string t = q1.front();
q1.pop();
if (dist1[t] > 10) break;
if (dist2.count(t) != 0) {
res = dist1[t] + dist2[t];
break;
}
//从t可以走到哪里
for (auto [subsrc, subdst] : map_subsrc_subdst) {
int pos = 0;
while (t.find(subsrc, pos) != string::npos) {
pos = t.find(subsrc, pos);
string nt = t.substr(0, pos) + subdst + t.substr(pos + subsrc.size());
if (dist1.count(nt) == 0) { //nt没有被起点扩展到
q1.push(nt);
dist1[nt] = dist1[t] + 1;
}
pos += subsrc.size(); //更新pos
}
}
} else {
//扩展q2
string t = q2.front();
q2.pop();
if (dist2[t] > 10) break;
if (dist1.count(t) != 0) {
res = dist1[t] + dist2[t];
break;
}
//从t可以走到哪里
for (auto [subdst, subsrc] : map_subsrc_subdst) {
int pos = 0;
while (t.find(subsrc, pos) != string::npos) {
pos = t.find(subsrc, pos);
string nt = t.substr(0, pos) + subdst + t.substr(pos + subsrc.size());
if (dist2.count(nt) == 0) {//nt没有被终点扩展到
q2.push(nt);
dist2[nt] = dist2[t] + 1;
}
pos += subsrc.size(); //更新pos
}
}
}
}
if (res != -1) cout << res << endl;
else cout << "NO ANSWER!" << endl;
return 0;
}
题目2:179八数码
考察点:bfs或A星算法
C++代码如下:
方法1:使用bfs
#include <iostream>
#include <vector>
#include <unordered_map>
#include <queue>
#include <algorithm>
using namespace std;
unordered_map<string, pair<string,char>> map_node_prevnode;
int bfs(string start) {
string end = "12345678x";
queue<string> q;
q.push(start);
unordered_map<string, int> d;
d[start] = 0;
int dirs[4][2] = {{-1,0},{1,0},{0,-1},{0,1}}; //u,d,l,r
char ops[4] = {'u', 'd', 'l', 'r'};
while (!q.empty()) {
string t = q.front();
q.pop();
if (t == end) {
return d[t];
}
//t可以走到哪儿,可以走到new_t
int idx = t.find('x');
int i = idx / 3, j = idx % 3;
for (int k = 0; k < 4; ++k) {
int x = i + dirs[k][0], y = j + dirs[k][1];
if (x < 0 || x >= 3 || y < 0 || y >= 3) continue;
string new_t = t;
swap(new_t[idx], new_t[x * 3 + y]);
if (d.count(new_t)) continue;
d[new_t] = d[t] + 1; //可以走到new_t
q.push(new_t);
map_node_prevnode[new_t] = make_pair(t, ops[k]);
}
}
return -1;
}
int main() {
string start = "";
string end = "12345678x";
char c;
for (int i = 0; i < 9; ++i) {
cin >> c;
start += c;
}
int t = bfs(start);
if (t != -1) {
string path = "";
//从终点到起点
string node = end;
while (node != start) {
path += map_node_prevnode[node].second;
node = map_node_prevnode[node].first; //更新node
}
//翻转
reverse(path.begin(), path.end());
cout << path << endl;
} else {
cout << "unsolvable" << endl;
}
return 0;
}
方法2:使用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;
}
题目3:178第K短路
考点:A星算法
C++代码如下,
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
typedef pair<int, PII> PIII;
const int N = 1010, M = 200010;
int n, m, S, T, K;
int h[N], rh[N], e[M], w[M], ne[M], idx;
int dist[N], cnt[N];
bool st[N];
void add(int h[], int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void dijkstra() {
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, T});
memset(dist, 0x3f, sizeof dist);
dist[T] = 0;
while (heap.size()) {
auto t = heap.top();
heap.pop();
int ver = t.y;
if (st[ver]) continue;
st[ver] = true;
for (int i = rh[ver]; ~i; i = ne[i]) {
int j = e[i];
if (dist[j] > dist[ver] + w[i]) {
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
}
int astar() {
priority_queue<PIII, vector<PIII>, greater<PIII>> heap;
heap.push({dist[S], {0, S}});
while (heap.size()) {
auto t = heap.top();
heap.pop();
int ver = t.y.y, distance = t.y.x;
cnt[ver]++;
if (cnt[T] == K) return distance;
for (int i = h[ver]; ~i; i = ne[i]) {
int j = e[i];
if (cnt[j] < K) {
heap.push({distance + w[i] + dist[j], {distance + w[i], j}});
}
}
}
return -1;
}
int main() {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
memset(rh, -1, sizeof rh);
for (int i = 0; i < m; ++i) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(h, a, b, c);
add(rh, b, a, c);
}
scanf("%d%d%d", &S, &T, &K);
if (S == T) K++;
dijkstra();
printf("%d\n", astar());
return 0;
}