电子学会五级-搜索-宽搜

电子学会五级-搜索-宽搜

1 抓住那头牛
http://noi.openjudge.cn/ch0205/2971/

#include<bits/stdc++.h>
using namespace std;

int N,K;
const int MAXN=100000+5;
bool vis[MAXN];
int d[MAXN];
queue<int> q;
int main(){
	cin>>N>>K;
	if(N==K){
		cout<<0;
		return 0;
	}
		
	vis[N]=true;
	d[N]=0;
	q.push(N);
	while(!q.empty()){
		int NN=q.front();
		q.pop();
		int NN1=NN-1;
		int NN2=NN+1;
		int NN3=NN*2;
		if(NN1>=0 && NN1<=100000 && !vis[NN1]){
			d[NN1]=d[NN]+1;
			vis[NN1]=true;
			if(NN1==K){
				break;
			}
			q.push(NN1);
		}
		if(NN2>=0 && NN2<=100000 && !vis[NN2]){
			d[NN2]=d[NN]+1;
			vis[NN2]=true;
			if(NN2==K){
				break;
			}
			q.push(NN2);
		}
		if(NN3>=0 && NN3<=100000 && !vis[NN3]){
			d[NN3]=d[NN]+1;
			vis[NN3]=true;
			if(NN3==K){
				break;
			}
			q.push(NN3);
		}
	}
	cout<<d[K];
}

2 P1588 [USACO07OPEN]Catch That Cow S
https://www.luogu.com.cn/problem/P1588

#include<bits/stdc++.h>
using namespace std;

int t,x,y;
const int MAXN=100005,MAXN1=100000;
bool vis[MAXN];//是否已经计算过 
int dis[MAXN];//到每个点步数 

void bfs(){
	memset(vis,false,sizeof(vis));//数据恢复 
	memset(dis,0,sizeof(dis));//数据恢复
	queue<int > q;
	vis[x]=true;
	dis[x]=0;
	q.push(x);//加入自己到队列 
	
	while(!q.empty()){
		int xx = q.front();
		q.pop();
		int xxs[3]={xx+1,xx-1,xx*2};//三种情况 
		for(int i=0;i<3;i++){
			if(xxs[i]>0 && xxs[i]<MAXN1 && !vis[xxs[i]]){//未出界  未访问过 
				vis[xxs[i]]	= true;
				dis[xxs[i]] = dis[xx]+1;
				q.push(xxs[i]);
				if(xxs[i]==y){//找到退出 优化效率 
					break;
				}			
			}
		}
	}
	cout<<dis[y]<<endl;//输出最小步数 
}

int main(){
	cin>>t;
	for(int i=0;i<t;i++){//多组数据 
		cin>>x>>y;
		bfs();//bfs求 x y走的最小步数 
	}
}

3 奇怪的电梯
https://www.luogu.com.cn/problem/P1135

#include<bits/stdc++.h>
using namespace std;

const int MAXN=205; 
bool vis[MAXN];//是否走过 
int dis[MAXN],f[MAXN],N,A,B;//f记录录入数据 dis到这层的最小步数 

void bfs(){
	memset(dis,-1,sizeof(dis));//默认-1 说明不能到达 
	queue<int> q;
	dis[A]=0;
	vis[A]=true;
	q.push(A);//走过A后 dis vis q设置对应值 
	
	while(!q.empty()){
		int AA=q.front();
		if(AA==B){//如果已经是B 不需要继续走到达B的下一楼梯 
			break;
		}
		q.pop();
		int AAs[2]={AA+f[AA],AA-f[AA]};//向上和向上两个方向 
		for(int i=0;i<2;i++){//两个方向分别尝试走 
		    //在电梯可上下范围 并且没到达过 --没到达过说明第一次到达 保证按键次数最小 
			if(AAs[i]>=1 && AAs[i]<=N && !vis[AAs[i]]){ 
				vis[AAs[i]]=true;
				dis[AAs[i]]=dis[AA]+1;
				q.push(AAs[i]);//走AAs[i]后 dis vis q设置对应值 
			}
		}
	}
}

int main(){
	cin>>N>>A>>B;
	for(int i=1;i<=N;i++){//录入数据到f 
		cin>>f[i];
	}
	bfs();//bfs模拟上下走 直到到达B为止 
	cout<<dis[B];//输出到B最少按键次数 
}

4 红与黑
http://noi.openjudge.cn/ch0205/1818/

#include<bits/stdc++.h>
using namespace std;

const int MAXN=30;//矩阵行 列 不超过 30 
char ipt[MAXN][MAXN];// 输入字符 
bool v[MAXN][MAXN];//此位置是否走过 
int dy[]={1,-1,0,0};//上下左右四个位置对应的y 
int dx[]={0,0,-1,1};//上下左右四个位置对应的x
int w,h,x,y,sum;//w宽 h高 x水平方向 y竖直方向 sum可走位置累计 
void bfs(){
	sum=0;
	queue<pair<int,int> > q;
	v[y][x]=true;
	sum++;
	q.push(make_pair(y,x));//走过 y行x列 
	
	while(!q.empty()){
		int yy=q.front().first;
		int xx=q.front().second;
		q.pop();
		for(int i=0;i<4;i++){//四个方向走 
			int yyy=yy+dy[i];
			int xxx=xx+dx[i];
			//在边界范围  没走过  可以走 
			if(yyy>=0 && yyy<h && xxx>=0 && xxx<w && !v[yyy][xxx] && ipt[yyy][xxx]=='.'){
				v[yyy][xxx]=true;
				sum++;
				q.push(make_pair(yyy,xxx));
			}
		} 
	}
}

int main(){
	while(cin>>w>>h){
		if(w==0 && h==0) break;
		memset(v,false,sizeof(v));
		memset(ipt,' ',sizeof(ipt));
		for(int i=0;i<h;i++){
			for(int j=0;j<w;j++){
				cin>>ipt[i][j];
				if(ipt[i][j]=='@'){//找到开始位置 
					y=i;x=j;		
				}
			}
		}
		bfs();
		cout<<sum<<endl;
	}
	
}

/*
3 3
...
#@.
...
0 0

*/

pair
https://blog.csdn.net/lwgkzl/article/details/84202383

5 马的遍历
https://www.luogu.com.cn/problem/P1443

#include<bits/stdc++.h>
using namespace std;

const int MAXM=405,MAXN=405;
const int dx[8]={-1,-2,-2,-1,1,2,2,1};
const int dy[8]={2,1,-1,-2,2,1,-1,-2};//8个方向
int n,m,x,y;
int vis[MAXM][MAXN];
int f[MAXM][MAXN];
queue<pair<int,int> > q;

int main(){
	memset(vis,false,sizeof(vis));
	memset(f,-1,sizeof(f));
	cin>>n>>m>>x>>y;
	f[x][y]=0;
	vis[x][y]=true;
	q.push(make_pair(x,y));
	while(!q.empty()){
		int xx = q.front().first;
		int yy = q.front().second;
		q.pop();
		for(int i=0;i<8;i++){
			int xxx = xx+dx[i];
			int yyy = yy+dy[i];
			if(xxx>n || xxx<1 || yyy >m || yy <1 || vis[xxx][yyy]) continue;
			
			vis[xxx][yyy]=true;
			q.push(make_pair(xxx,yyy));
			f[xxx][yyy]=f[xx][yy]+1;
		}
	}
	
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			printf("%-5d",f[i][j]);
		}
		printf("\n");
	}
}

6 Meteor Shower S
https://www.luogu.com.cn/problem/P2895

#include<bits/stdc++.h>
using namespace std;
const int MAXN=305;
bool vis[MAXN][MAXN],flag;
//f记录坐标被撞击的最小时间 dis记录从0 0走到此处用到时间 
int f[MAXN][MAXN],dis[MAXN][MAXN],M;
int dy[]={-1,0,0,1};
int dx[]={0,-1,1,0};//上下左右四个方向 
void bfs(){
	queue<pair<int,int> > q;
	vis[0][0]=true;
	dis[0][0]=0;
	q.push(make_pair(0,0));//从0 0开始走 
	
	while(!q.empty()){
		int yy = q.front().first;
		int xx = q.front().second;
		q.pop();
		for(int i=0;i<4;i++){//四个方向扩展 
			int yyy=yy+dy[i];
			int xxx=xx+dx[i];
			if(xxx>=0 && xxx<=301 && yyy>=0 && yyy<=301 && !vis[yyy][xxx] ){
				//不会被流行撞击的位置 默认为0x3f3f3f3f 
				if(f[yyy][xxx]==0x3f3f3f3f){//找到输出到达时间为最小时间 
					cout<<dis[yy][xx]+1;
					flag=true;
					return;
				}
				//在流星撞击前走过 否则此路无法通过 
				if(dis[yy][xx]+1<f[yyy][xxx]){ 
					vis[yyy][xxx]=true;
					dis[yyy][xxx]=dis[yy][xx]+1;
					q.push(make_pair(yyy,xxx));
				}
			}
		}
	}
}

int main(){
	memset(dis,-1,sizeof(dis));//初始 -1 
	memset(f,0x3f,sizeof(f));//初始 0x3f3f3f3f int四个字节 
	cin>>M;
	for(int i=0;i<M;i++){//输入 初始化数据 
		int x,y,t;
		cin>>x>>y>>t;
		//默认很大的数 撞击点和撞击四周点都可能改变此值,保持最小 
		f[y][x]=min(f[y][x],t); 
		for(int j=0;j<4;j++){
			int yy=y+dy[j];
			int xx=x+dx[j];
			//撞击四周点在边界范围 同撞击点一样修改 使此坐标值更小
			if(xx>=0 && yy>=0) {//先受到撞击后续就无法通过 
				f[yy][xx]=min(f[yy][xx],t);
			}
		}
	}

	bfs();
	if(!flag)//无法通过  输出-1 
		cout<<-1; 
}

7 Lake Counting S
https://www.luogu.com.cn/problem/P1596

#include<bits/stdc++.h>
using namespace std;

const int N=105;
int n,m,ans;
char a[N][N];
bool v[N][N];
int dy[]={0,-1,-1,-1,0,1,1,1};
int dx[]={-1,-1,0,1,1,1,0,-1};
/*
	通过一个水点 把周围水点都标识被此水坑占用 
*/ 
void bfs(int y,int x){
	queue<pair<int,int> > q;
	v[y][x]=true;
	q.push(make_pair(y,x));
	while(!q.empty()){
		int yy=q.front().first;
		int xx=q.front().second;
		q.pop();
		for(int i=0;i<8;i++){
			int yyy=yy+dy[i];
			int xxx=xx+dx[i];
			if(yyy>=0 && yyy<n && xxx>=0 && xxx<m && a[yyy][xxx]=='W' && !v[yyy][xxx]){
				v[yyy][xxx]=true;
				q.push(make_pair(yyy,xxx));
			}
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>a[i][j];
		}
	}
	
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(a[i][j]=='W' && !v[i][j]){
				//找到有水 并且没有被标识过的点 --说明找到一个水坑
				//找到一个点后,会通过bfs把周边有水的点都标识被水坑占用 
				ans++; 
				bfs(i,j);
			}
		}
	}
	cout<<ans;
}

8 Corn Maze S
https://www.luogu.com.cn/problem/P1825

#include<bits/stdc++.h>
using namespace std;

const int N=305;
int n,m,sx,sy;
char a[N][N];//输入字符 
bool v[N][N];//是否已经走过 

int dx[]={-1,1,0,0};//四个方向 行 
int dy[]={0,0,-1,1};//四个方向 列

struct xy{//点坐标 以及走到此点步数 
	int x,y,step;
	xy(){
		x=y=-1;
		step=0;
	}
};

struct pxy{
	xy p1,p2;
}pxys[N];//存储可以直达字母对 

void bfs(){
	queue<xy> q; 
	xy sxy;
	sxy.x=sx,sxy.y=sy,sxy.step=0;
	q.push(sxy);//起点放入队列
	while(!q.empty()){
		xy xyt=q.front();
		q.pop();
		if(a[xyt.x][xyt.y]=='='){//= 退出 
			cout<<xyt.step;
			return;
		}
		for(int i=0;i<4;i++){//四个方向 
			xy xytt;
			xytt.x=xyt.x+dx[i];
			xytt.y=xyt.y+dy[i];
			//在范围内  没走过  可以走 
			if(xytt.x>=0 && xytt.x<n && xytt.y>=0 && xytt.y<m && !v[xytt.x][xytt.y] && a[xytt.x][xytt.y]!='#'){
				if(a[xytt.x][xytt.y]<'A' || a[xytt.x][xytt.y]>'Z'){//不是大写字母 直接走一步 
					xytt.step=xyt.step+1;
					v[xytt.x][xytt.y]=true;
				}else{//是大写字母 取出此字母相对位置 
					int idx=a[xytt.x][xytt.y]-'A';
					if(xytt.x==pxys[idx].p1.x && xytt.y == pxys[idx].p1.y){//和第1个字母相同 走到第2个字母 
						xytt.x=pxys[idx].p2.x;
						xytt.y=pxys[idx].p2.y;
						xytt.step=xyt.step+1;
					}else{//和第2个字母相同 走到第1个字母
						xytt.x=pxys[idx].p1.x;
						xytt.y=pxys[idx].p1.y;
						xytt.step=xyt.step+1;
					}
				}
				q.push(xytt); 
			}
		}
	}	
}

int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>a[i][j];
			if(a[i][j]=='@'){//记录起点 
				sx=i,sy=j;
			}
			if(a[i][j]>='A' && a[i][j]<='Z'){
				int tasci=a[i][j]-'A';
				if(pxys[tasci].p1.x==-1){//通过字母找到此字母两个位置  
					pxys[tasci].p1.x=i;
					pxys[tasci].p1.y=j;					
				}else{
					pxys[tasci].p2.x=i;
					pxys[tasci].p2.y=j;
				}
			}
		}
	}
	
	bfs();
	
	return 0;
} 

1253:Dungeon Master
http://noi.openjudge.cn/ch0205/1253/

八数码
https://www.luogu.com.cn/problem/P1379

posted @ 2022-09-30 16:20  new-code  阅读(21)  评论(0编辑  收藏  举报