BFS:双向广搜、A*优化
程序员文章站
2022-06-03 23:38:41
...
#写在前面
无
#双向广搜
从两个方向同时搜索
双向广搜一般用在最小步数模型的题目里
一个点扩展出的点比较多(指数级别)
##字串变换
https://www.acwing.com/problem/content/192/
----c++版
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#include<queue>
using namespace std;
const int N=6;
string a[N], b[N];
int n=0;
int extend(queue<string> &q, unordered_map<string, int> &da, unordered_map<string, int> &db, string a[], string b[]){
string t=q.front();
q.pop();
for(int i=0; i<t.size(); i++)//枚举当前字符串的每一个字符
for(int j=0; j<n; j++)//枚举规则
if(t.substr(i, a[j].size())==a[j]){
string state = t.substr(0, i)+b[j]+t.substr(i+a[j].size());//组成新的子串
if(db.count(state)) return da[t]+1+db[state];//只有搜到了才会返回值,不然一直是11
if(da.count(state))continue;//a已经扩展到了
da[state]=da[t]+1;
q.push(state);
}
return 11;
}
int bfs(string A, string B){
queue<string> qa, qb;
unordered_map<string, int> da, db; //存每个状态到起点和终点的距离
qa.push(A), da[A]=0;
qb.push(B), db[B]=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);
if(t<=10) return t;//只有搜到了才会小于11
}
return 11;//如果最后两方都遍历完了还不连通,说明无解
}
int main(){
string A,B;
cin>>A>>B;
while(cin>>a[n]>>b[n])n++;
int step=bfs(A,B);
if(step>10)puts("NO ANSWER!");
else printf("%d", step);
return 0;
}
#A*优化
中间所有点第一次出队不一定是最优解,每个点不只被扩展一次
只有终点第一次出队是最优解!!!
##八数码之A*优化版
https://www.acwing.com/problem/content/181/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<unordered_map>
using namespace std;
#define x first
#define y second
typedef pair<int, string> pis;
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){
string end="12345678x";
unordered_map<string, int> dist;
unordered_map<string, pair<char, string>> prev;//记录前驱状态
priority_queue<pis, vector<pis>, greater<pis>> heap;
dist[start]=0;
heap.push({f(start), start});
int dx[4]={-1,0, 1, 0}, dy[4]={0, 1, 0, -1};//上右下左
char op[4]={'u','r','d','l'};
while(heap.size()){
auto t=heap.top();
heap.pop();
string state=t.y;
if(state==end)break;
int x,y;//找空格的坐标
for(int i=0; i<9 ;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)continue;
state=source;
swap(state[x*3+y], state[a*3+b]);
if(!dist.count(state)||dist[state]>dist[source]+1){//之前没被扩展过或者是之前扩展的距离比较大
dist[state]=dist[source]+1;
prev[state]={op[i], source};
heap.push({f(state)+dist[state], state});
}
}
}
string res;
while(end!=start){
res+=prev[end].x;
end=prev[end].y;
}
reverse(res.begin(), res.end());
return res;
}
int main(){
string start, seq;
char c;
while(cin>>c){
start+=c;
if(c!='x')seq+=c;
}
int cnt=0;//求逆序对
for(int i=0; i<8; i++)
for(int j=i; j<8; j++)
if(seq[i]>seq[j])
cnt++;
if(cnt&1)puts("unsolvable");
else cout<<bfs(start)<<endl;
return 0;
}
##第K短路
https://www.acwing.com/problem/content/180/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define x first
#define y second
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];
int st[N];
int cnt[N];//不加就tle
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++;//多了一条为0的最短路
dijkstra();
printf("%d\n", astar());
return 0;
}
上一篇: Android之耳机音量加大时警告提示框问题(MTK6739平台)
下一篇: 活动的启动方式