双端队列广搜
电路维修
原题链接
#include<iostream>
#include<algorithm>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<queue>
#define int long long
#define fi first
#define se second
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef pair<int,int> pii;
const int N= 510;
char g[N][N];
int n,m;
int dist[N][N];
bool st[N][N];
int dx[4]={-1,-1,1,1},dy[4]={-1,1,1,-1};
int ix[4]={-1,-1,0,0},iy[4]={-1,0,0,-1};
pii pre[N][N];
int bfs(int x,int y){
memset(dist,0x3f,sizeof dist);
memset(st,false,sizeof st);
deque<pii> q;
q.push_front({x,y});
dist[x][y]=0;
char s[]="\\/\\/";
while(q.size()){
auto t=q.front();
q.pop_front();
for(int i=0;i<4;i++){
int tx=t.fi+dx[i],ty=t.se+dy[i];
int sx=t.fi+ix[i],sy=t.se+iy[i];
if(tx<0||tx>n||ty<0||ty>m) continue;
int d=(g[sx][sy]!=s[i]);
if(dist[tx][ty]>dist[t.fi][t.se]+d)
if(d){
q.push_back({tx,ty});
dist[tx][ty]=dist[t.fi][t.se]+d;
pre[tx][ty]=t;
}else{
q.push_front({tx,ty});
dist[tx][ty]=dist[t.fi][t.se]+d;
pre[tx][ty]=t;
}
}
}
return dist[n][m];
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t;
cin>>t;
while(t--){
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>g[i][j];
if(n+m&1){
cout<<"NO SOLUTION"<<endl;
}
else cout<<bfs(0,0)<<endl;
}
return 0;
}
debug
- 不能用距离的初始化数值来判断跳过,因为权值有为0的时候,所以第一次进入队列的点不一定是最小的,要一直更新。
- 关闭同步流后,混用puts和cout,使得输入输出顺序发生变化。
- \这个要用转义符
总结
- 双向队列广搜是解决权值为0,1求最短问题的方法。
- \转义符的使用,字符串的定义——“\/\/”,{ }
- 这种权值为0,或者第一次进入队列不一定是距离最小的情况,不能用初始值跳过。
- 关闭同步流后一定要注意不要混用c语言中的输入输出。
- 当数组为long long时,inf要用0x3f3f3f3f3f3f3f3f,八个3f。
双向广搜
字串变换
原题链接
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define int long long
#define fi first
#define se second
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef pair<int, int>pii;
const int N = 10;
string A,B;
string a[N],b[N];
int n;
int extend(queue<string> &q,map<string,int> &da,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 state=t.substr(0,j)+b[i]+t.substr(j+a[i].size());
if(db.count(state)) return da[t]+db[state]+1;
if(da.count(state)) continue;
q.push(state);
da[state]=da[t]+1;
}
}
}
}
return 11;
}
int bfs(string A,string B){
if(A==B) return 0;
queue<string> qa,qb;
map<string,int> da,db;
qa.push(A),qb.push(B);
da[A]=0,db[B]=0;
int t,step=0;
while(qa.size()&&qb.size()){
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;
if(++step>10) return 11;
}
return 11;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>A>>B;
while(cin>>a[n]>>b[n]) n++;
int t=bfs(A,B);
if(t<=10) cout<<t;
else cout<<"NO ANSWER!";
return 0;
}
debug
- bfs里面居然忘了while队列不空
- extend和bfs函数里面完了记得返回不符要求的数。
- 特判一定要注意
- substr前面要用t.substr(),front()不要忘记括号
- a[i]替换成b[i]
总结
- 双向广搜用于解空间非常的大,然后求最小这种性质
- 广搜的不走,两个队列,谁小就扩展谁,轮流扩展
- map就当距离的用法dist,然后注意判断有没有要用count函数。