电子学会五级-搜索-宽搜
电子学会五级-搜索-宽搜
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/
作者:newcode 更多资源请关注纽扣编程微信公众号
从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习