百炼4116 拯救行动4130 Saving Tang Monk4115 鸣人与佐助 简单BFS搜索题型总结对比

news/2024/11/2 0:31:35/

一、

百炼4116拯救行动(OpenJudge - 4116:拯救行动)

        这题就是在简单BFS的基础上加了一个守卫,击杀一次守卫时间也需要+1,其他照常按照普通BFS的思路就行,最主要就是可以把击杀守卫看成是经过两次这一个点,这样就不用对击杀守卫做时间+2的特殊处理。这题与下面要讲的两题不同的地方就是被另一条(因为BFS是很多条路同时搜索)BFS所走路径击杀的守卫在其他路径上就不必在次击杀了(如果该守卫已经被击杀了那么一定有另一条路比当前路径更短,所以此路就没有必要再往这边走了)如果明白了这一点画个图就很任意区分这几题的区别。

先解释一下怎么样把击杀守卫看成两次经过这个点,先看图

struct point{int x;int y;int step;int flag;point(int a,int b,int c,int d):x(a),y(b),step(c),flag(d){}point(){}
};

首先用flag来标记当前位置是否是守卫。

if(u.flag==1)
{r.push(point(u.x,u.y,u.step+1,0));continue;
}

当前位置的flag==1的时候会再次把当前点入队(如上图),就相当于走了两次这个位置。

下面是本题ac代码

#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
char mp[210][210];
int v[210][210];
int xr,yr,xa,ya;int n,m;
int Dx[4]={0,1,0,-1};
int Dy[4]={1,0,-1,0};
struct point{int x;int y;int step;int flag;point(int a,int b,int c,int d):x(a),y(b),step(c),flag(d){}point(){}
};
struct point u,p;
int Bfs()
{queue<point> r;r.push(point(xr,yr,0,0));while(!r.empty()){u=r.front();r.pop();if(u.flag==1){r.push(point(u.x,u.y,u.step+1,0));continue;}if(mp[u.x][u.y]=='a'){return u.step;}for(int i=0;i<4;i++){p.x=u.x+Dx[i];p.y=u.y+Dy[i];if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m&&v[p.x][p.y]==0){if(mp[p.x][p.y]=='@'||mp[p.x][p.y]=='a'){r.push(point(p.x,p.y,u.step+1,0));}if(mp[p.x][p.y]=='x'){r.push(point(p.x,p.y,u.step+1,1));}v[p.x][p.y]=1;}}}return 0;
}
int main()
{int t;cin>>t;while(t--){cin>>n>>m;for(int i=0;i<n;i++){scanf("%s",mp[i]);}for(int i=0;i<n;i++){for(int j=0;j<m;j++){v[i][j]=0;if(mp[i][j]=='r'){xr=i;yr=j;v[i][j]=1;}}}int ans=Bfs();if(ans==0)printf("Impossible\n");else{printf("%d\n",ans);}}return 0;
}

二、

百炼4115 鸣人与佐助(OpenJudge - 4115:鸣人和佐助)

        先列出一个图简单说明与上一题的区别

 如果查克拉数量是3,如果本题不重复杀死其他路径杀死的蛇那么某些情况将无解,所以本题和上题的区别就是要重复走其他路径走过的路。明白了这一点就好做了,记录是否被访问用一个三维数组,不光记录坐标还要记录当前查克拉的数量,只有当查克拉数量相同并且当前点被访问过才不需要重复访问(因为查克拉相同说明击杀的蛇数量相同,被访问过说明有一条比当前更优的路)

理解了这些这一题就基本出来了,下面放出ac代码

#include<iostream>
#include<queue>
using namespace std;
char mp[210][210];
int v[210][210][20];
int Dx[4]={0,1,0,-1};
int Dy[4]={1,0,-1,0};
int m,n,k;
int xr,yr,xe,ye;
struct point{int x,y,t,k;point(int a,int b,int c,int d):x(a),y(b),t(c),k(d){}point(){}
};
queue<point> q;
struct point u;
int bfs()
{v[xr][yr][k]=1;q.push(point(xr,yr,0,k));while(!q.empty()){u=q.front();q.pop();if(u.x==xe&&u.y==ye)return u.t;for(int i=0;i<4;i++){int nx=u.x+Dx[i];int ny=u.y+Dy[i];if(nx<0||ny<0||nx>=m||ny>=n)continue;if(mp[nx][ny]=='#'&&v[nx][ny][u.k-1]==0&&u.k>0)//遇到敌人而且在当前剩余差拉克数量相同的时候当前走的路径最短{v[nx][ny][u.k-1]=1;q.push(point(nx,ny,u.t+1,u.k-1));}else if(mp[nx][ny]!='#'&&v[nx][ny][u.k]==0)//点前k数量相同的时候如果已经走过的路,先走的最短,就没有必要走了{v[nx][ny][u.k]=1;q.push(point(nx,ny,u.t+1,u.k));}}}return 0;
}
int main()
{while(cin>>m>>n>>k){for(int i=0;i<m;i++)for(int j=0;j<n;j++){char c;cin>>c;mp[i][j]=c;if(c=='@'){xr=i;yr=j;}if(c=='+'){xe=i;ye=j;}}int ans=bfs();if(ans)printf("%d\n",ans);elseprintf("-1\n");}return 0;
}

三、

百炼4130 Saving Tang Monk(OpenJudge - 4130:Saving Tang Monk)

        这一题就和上一题就很相似了,这一题的钥匙的作用就相当于查克拉,但是比上一题多一个找钥匙的步骤,钥匙只能找比当前获得的钥匙编号大1的钥匙,还有一个就是重复访问钥匙房间,比如当前找到了钥匙2,那么就不能继续访问其他路径访问过的钥匙2房间,因为另一条路一定比当前路径更短(因为先找到2钥匙),所以这里处理和上一题是一样的用一个三维数组来记录坐标和钥匙编号。但是这一题的难点就是在找钥匙的时候同一条路径是可以来回走,因为钥匙是按顺序来找的,这时对杀蛇怎么处理。例如在当前路径上需要先去杀蛇拿到钥匙1再回来拿钥匙2,就需要两次经过同一个有蛇的房间,这时就需要钥匙的三维数组和蛇的状态同时配合使用来标记一条路径上蓑鲉蛇的状态,这里用到了状态压缩,用二进制数来表示每一条蛇,如下代码

if(isalpha(mp[nx][ny]))
{bool killed=(1<<(mp[nx][ny]-'A'))&snack;int ns=snack+(1<<(mp[nx][ny]-'A'));if(killed&&!v[nx][ny][key]) {Q.push(point(nx,ny,time+1,key,snack));v[nx][ny][key]=1;}else if(!killed&&!v[nx][ny][key]) {v[nx][ny][key]=1;Q.push(point(nx,ny,time+2,key,ns));}
}

比如下一个点的蛇没有被杀的时候将当前蛇(假设是遇到的第一条蛇)设置(利用int ns=snack+(1<<(mp[nx][ny]-'A'));)为0001,第二条蛇0011以此类推,再用蛇的编号进行&运算得出是否被杀死。当然当key相同而且在另一条路径上该蛇已经被杀死了,那么当前路径就没有必要重复了(因为另一条路径一定更短)下面给出ac代码(参考了这篇博客)特此感谢

#include<iostream>
#include<cstdio>
#include<queue>
#include<string.h>
using namespace std;
int n,k;
int xk,yk,xt,yt;
char mp[110][110];
int v[110][100][10];
int Dx[4]={0,1,0,-1};
int Dy[4]={1,0,-1,0};
struct point{int x,y,time,key,snack;point(int a,int b,int c,int d,int e):x(a),y(b),time(c),key(d),snack(e){}bool operator < (const point& p) const{return time>p.time;}
};
int bfs(int xk,int yk)
{priority_queue <point> Q;Q.push(point(xk,yk,0,0,0));v[xk][yk][0]=1;while(!Q.empty()){int x=Q.top().x, y=Q.top().y, time=Q.top().time, key=Q.top().key,snack=Q.top().snack;Q.pop();if(key==k&&x==xt&&y==yt)return time;for(int i=0;i<4;i++){int nx=x+Dx[i];int ny=y+Dy[i];if(nx<0||ny<0||nx>=n||ny>=n||mp[nx][ny]=='#')continue;if(isalpha(mp[nx][ny])){bool killed=(1<<(mp[nx][ny]-'A'))&snack;int ns=snack+(1<<(mp[nx][ny]-'A'));if(killed&&!v[nx][ny][key]) {Q.push(point(nx,ny,time+1,key,snack));v[nx][ny][key]=1;}else if(!killed&&!v[nx][ny][key]) {v[nx][ny][key]=1;Q.push(point(nx,ny,time+2,key,ns));}}else{if(v[nx][ny][key]==0){v[nx][ny][key]=1;Q.push(point(nx,ny,time+1,key,snack));}if(isdigit(mp[nx][ny])){int nkey = mp[nx][ny]-'0';if(nkey==key+1&&v[nx][ny][nkey]==0){Q.push(point(nx,ny,time+1,nkey,snack));v[nx][ny][nkey]=1;}}}}}return -1;
}
int main()
{while(cin>>n>>k){if(n==0)break;int snake=0;for(int i=0;i<n;i++){scanf("%s",mp[i]);}for(int i=0;i<n;i++)for(int j=0;j<n;j++){if(mp[i][j]=='K'){mp[i][j]='.';xk=i;yk=j;}else if(mp[i][j]=='T'){mp[i][j]='.';xt=i;yt=j;}else if(mp[i][j]=='S'){mp[i][j]='A'+snake++;}}memset(v,0,sizeof(v));int ans=bfs(xk,yk);if(ans==-1) cout<<"impossible"<<endl;else cout<<ans<<endl;}return 0;
}


http://www.ppmy.cn/news/221957.html

相关文章

BZOJ4130:[PA2011]Kangaroos

浅谈\(K-D\ Tree\)&#xff1a;https://www.cnblogs.com/AKMer/p/10387266.html 题目传送门&#xff1a;https://lydsy.com/JudgeOnline/problem.php?id4130 这题跟\(BZOJ4358:permu\)一样。 不过我们需要把区间包含某个点改成判断区间是否有交点。 假设我们有俩区间\([l,r]\)…

百练4130:Saving Tang Monk

英文题目巨烦 紧接着百练4115:鸣人和佐助和百练4116拯救行动的变形 题目连接&#xff1a;http://bailian.openjudge.cn/practice/4130/ #include<iostream> #include<algorithm> #include<fstream> #include<cstdlib> #include<cstring> #inc…

Gigabayte-Z87-DS3H i3 4130电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板Gigabayte-Z87-DS3H 处理器英特尔酷睿i3 4130 Haswell已驱动 内存4x4GB DDR3/1600Mhz金士顿已驱动 硬盘SSD 480GB PNY CS900已驱动 显卡英特尔高…

[jzoj 1214] [luogu 4130] [NOI2007]项链工厂 {线段树}

题目 https://www.luogu.org/problemnew/show/P4130 解题思路 S p l a y 不 会 \color{red}Splay不会 Splay不会&#xff0c;那就正经的打线段树。 这道题目的后4问&#xff0c;就是纯正的线段树。 对于前两问&#xff0c;其实只是改变了每一个端点的位置&#xff0c;但没有改…

二分查找 ZOJ4130

ZOJ4130 题目链接在此&#xff01; 题目大意&#xff1a; 关灯问题。 总共n个灯&#xff0c;然后给状态&#xff0c;一次能关掉连续的m个灯。 关灯k次就能成功&#xff0c;问最少的m。 注意&#xff01;不是改变状态&#xff01;是关掉&#xff01;0不会重新变成1的。 题目…

zoj 4130(The 16th Zhejiang Provincial Collegiate Programming Contest D)(思维)

传送门&#xff1a; 题意&#xff1a; 你现在有nnn个点&#xff0c;对于第iii个点&#xff0c;可以到达第i−1i-1i−1、2∗i2*i2∗i、2∗(i1)2*(i1)2∗(i1)、⌊i2⌋\left \lfloor \frac{i}{2} \right \rfloor⌊2i​⌋号点。现在问你从111号点开始的哈密顿路径。 分析&#xff1…

ZOJ -4130 Turn It Off

题目描述&#xff1a; Its already 21:30 now, and its time for BaoBao to go to bed. To ensure his sleeping quality, BaoBao decides to turn all the lights in his bedroom off. There are n lights, numbered from 1 to n, arranged in a row in BaoBaos bedroom. Ea…

“同档位无对手”的荣耀90系列,有哪些厉害的能力?

5 月 29 日&#xff0c;荣耀90系列正式发布。该系列包括荣耀90 Pro与荣耀90两款机型。 这两款机型都有哪些厉害的能力&#xff1f; 一、赵明&#xff1a;荣耀90系列“同档位无对手” 发布会在天府之国的成都市举行&#xff0c;这个以时尚和美食著称的城市&#xff0c;近年来…