10.3
BFS
题目列表
A
dfs求连通性
把所有1的点能联通的点,全部消掉,计数,依次
上码
#include <bits/stdc++.h>
using namespace std;////23058720
const int N=1010;
int mp[N][N],n,m;
int dx[]={0,0,1,-1,1,-1,1,-1};
int dy[]={1,-1,0,0,1,1,-1,-1};
void dfs(int x,int y){
for(int i=0;i<8;i++){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1||xx>n||yy<1||y>m)continue;
if(mp[xx][yy]==1){
mp[xx][yy]=0;
dfs(xx,yy);
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin>>c;
if(c=='w')mp[i][j]=1;
}
}
int num=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]){
dfs(i,j);
num++;
}
}
}
cout<<num<<endl;
return 0;
}
B
一道网格图最短路问题,显然只搜到一条x-y的最短路径就可以了,不用搜出所有路径,选用bfs
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
char mp[N][N];
int n,m,dis[N][N];
int dx[] ={2, 2, 1, 1, -1, -1, -2, -2};
int dy[] ={1, -1, 2, -2, -2, 2, 1, -1};
int sx,sy,ex,ey;
void bfs(){
queue<pair<int ,int > >q;
dis[sx][sy]=0;
q.push({sx,sy});
while(!q.empty()){
int x=q.front().first;
int y=q.front().second;
if(mp[x][y]=='H'){
cout<<dis[x][y]<<endl;
return;
}
q.pop();
for(int i=0;i<8;i++){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>m||mp[xx][yy]=='*'||dis[xx][yy]!=-1)continue;
dis[xx][yy]=dis[x][y]+1;
q.push({xx,yy});
}
}
}
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp[i][j];
if(mp[i][j]=='K'){
sx=i,sy=j;
}
if(mp[i][j]=='H'){
ex=i,ey=j;
}
dis[i][j]=-1;
}
}
bfs();
return 0;
}
C
求每个0到离它最近的1的曼哈顿距离
把曼哈顿距离转化为上下左右去扩展
第一种办法:对于每一0去跑bfs,每次只能得到一个点的答案,bfs时间复杂度为O(nn),显然会超时
正解:对于每一个1去跑bfs,跑一次得到的点的答案为1-nn,时间复杂度降低
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,m;
char mp[N][N];
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int dis[N][N];
void bfs(){
memset(dis,-1,sizeof dis);
queue<pair<int ,int > >q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='1'){
q.push({i,j});
dis[i][j]=0;
}
}
}
while(!q.empty()){
int x=q.front().first;
int y=q.front().second;
q.pop();
for(int i=0;i<4;i++){
int xx=x+dx[i];
int yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>m||dis[xx][yy]!=-1)continue;
dis[xx][yy]=dis[x][y]+1;
q.push({xx,yy});
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>mp[i][j];
}
}
bfs();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cout<<dis[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
D
上难度了
对于A B C三种操作
A:倒序
B:设原字符串为s(0,n-1),s0=s3,s1=s0,s2=s1,s3=s2,s4=s5,s5=s6,s6=s7,s7=s4,
C:s1=s6,s2=s1,s5=s2,s6=s5
用一个哈希表标记,防止重复
对于每一种状态跑bfs,搜出他的三个状态,如果相等,直接退出,bfs(确保是最短的的)
代码
#include <bits/stdc++.h>
using namespace std;
string a;
unordered_map<string ,string> mp;
queue<string>q;
void A(string s){
string ss=s;
for(int i=0;i<4;i++){
char x1=s[i];
s[i]=s[7-i];
s[7-i]=x1;
}
if(mp.count(s)==0){
q.push(s);
mp[s]=mp[ss]+'A';
}
}
void B(string s){
string ss=s;
s[0]=ss[3],s[1]=ss[0],s[2]=ss[1],s[3]=ss[2],s[4]=ss[5],s[5]=ss[6],s[6]=ss[7],s[7]=ss[4];
if(mp.count(s)==0){
q.push(s);
mp[s]=mp[ss]+'B';
}
}
void C(string s){
string ss=s;
s[1]=ss[6],s[2]=ss[1],s[5]=ss[2],s[6]=ss[5];
if(mp.count(s)==0){
q.push(s);
mp[s]=mp[ss]+'C';
}
}
void bfs(){
q.push("12345678");
mp["12345678"]="";
while(!q.empty()){
string x=q.front();
q.pop();
A(x),B(x),C(x);
if(mp.count(a)!=0){
cout<<mp[a].size()<<endl<<mp[a]<<endl;
return;
}
}
}
int main(){
for(int i=1;i<=8;i++){
char c;
cin>>c;
a+=c;
getchar();
}
bfs();
return 0;
}
E
远古老题
双向广搜
例如在已知终点和起点的情况下求是否能到达,需要走多远路。那既然已知终点,为何不从终点同时开始进行搜索,看看是否能在中间相遇。
方法:分成两个队列。正向 BFS 和逆向 BFS 的队列分开。让子状态少的 BFS 先扩展下一层,另一个子状态多的 BFS 后扩展,任一队列的状态扩展完后就结束,可以减少搜索的总状态数,尽快相遇。双向广搜在扩展队列时也需要处理去重问题。把状态入队列的时候,先判断这个状态是否曾经入队,如果重复了,就丢弃。
F
bfs/dfs求联通性板子
剪枝(迭代加深,最优性剪枝,记忆化,可行性剪枝,搜索顺序),搜索树
dfs 指数,排列,组合

浙公网安备 33010602011771号