搜索篇 ——洛谷
一、马的遍历
题目链接:P1443 马的遍历 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
有一个 n * m 的棋盘,在某个点 (x, y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。(中国象棋里面的马,不知道怎么走的小伙伴可以百度)。
输入格式
输入只有一行四个整数,分别为 n, m, x, y。
输出格式
一个 n * m 的矩阵,代表马到达某个点最少要走几步(左对齐,宽 5 格,不能到达则输出 −1)。
输入输出样例
输入 #1
3 3 1 1
输出 #1
0 3 2
3 -1 1
2 1 4
数据规模
对于全部的测试点,保证 1 ≤ x ≤ n ≤ 400, 1 ≤ y ≤ m ≤ 400。
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 500;
const int dx[8] = {-1,1,-1,1,-2,2,-2,2};
const int dy[8] = {2,2,-2,-2,1,1,-1,-1};
int vis[N][N];
int step[N][N];
int main(){
int n,m,sx,sy; cin >> n >> m >> sx >> sy;
queue<PII> que;
memset(step,-1,sizeof step); memset(vis,0,sizeof vis);
vis[sx][sy] = 1, step[sx][sy] = 0;
que.push({sx,sy});
while(!que.empty()){
PII temp = que.front(); que.pop();
for(int i = 0; i < 8; i++){
int nx = dx[i] + temp.first, ny = dy[i] + temp.second;
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny]) continue;
step[nx][ny] = step[temp.first][temp.second] + 1;
que.push({nx,ny});
vis[nx][ny] = 1;
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++)
printf("%-5d",step[i][j]);
printf("\n");
}
return 0;
}
二、好奇怪的游戏
题目链接:P1747 好奇怪的游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
爱与愁大神坐在公交车上无聊,于是玩起了手机。一款奇怪的游戏进入了爱与愁大神的眼帘:***(游戏名被打上了马赛克)。这个游戏类似象棋,但是只有黑白马各一匹,在点x1,y1和x2,y2上。它们得从点x1,y1和x2,y2走到1,1。这个游戏与普通象棋不同的地方是:马可以走“日”,也可以像象走“田”。现在爱与愁大神想知道两匹马到1,1的最少步数,你能帮他解决这个问题么?
输入格式
第1行:两个整数x1,y1
第2行:两个整数x2,y2
输出格式
第1行:黑马到1,1的步数
第2行:白马到1,1的步数
输入输出样例
输入 #1
12 16
18 10
输出 #1
8
9
数据范围
100%数据:x1,y1,x2,y2<=20
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 60;
const int dx[] = {-1,1,-1,1,-2,2,-2,2,2,2,-2,-2};
const int dy[] = {2,2,-2,-2,1,1,-1,-1,-2,2,-2,2};
int vis[N][N];
struct Node {
int x, y, step;
Node(int x, int y, int step){
this->x = x;
this->y = y;
this->step = step;
}
};
int bfs(int sx, int sy){
queue<Node> que;
que.push(Node(sx, sy, 0));
vis[sx][sy] = 1;
while(!que.empty()){
int x = que.front().x, y = que.front().y, step = que.front().step;
que.pop();
for(int i = 0; i < 12; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > 50 || ny < 1 || ny > 50 || vis[nx][ny]) continue;
if(nx == 1 && ny == 1) return step + 1;
que.push(Node(nx, ny, step + 1));
vis[nx][ny] = 1;
}
}
}
int main(){
int sx,sy;
cin >> sx >> sy;
cout << bfs(sx,sy) << endl;
memset(vis,0,sizeof(vis));
cin >> sx >> sy;
cout << bfs(sx,sy) << endl;
return 0;
}
三、离开中山路
题目链接:P1746 离开中山路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在x1,y1处,车站在x2,y2处。现在给出一个n×n(n<=1000)的地图,0表示马路,1表示店铺(不能从店铺穿过),爱与愁大神只能垂直或水平着在马路上行进。爱与愁大神为了节省时间,他要求最短到达目的地距离(a[i][j]距离为1)。你能帮他解决吗?
输入格式
第1行:一个数 n
第2行~第n+1行:整个地图描述(0表示马路,1表示店铺,注意两个数之间没有空格)
第n+2行:四个数 x1,y1,x2,y2
输出格式
只有1行:最短到达目的地距离
输入输出样例
输入 #1复制
3
001
101
100
1 1 3 3
输出 #1
4
数据范围
20%数据: n <= 100
100%数据:n <= 1000
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 1e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};
int vis[N][N];
int step[N][N];
char g[N][N];
int n, sx, sy, ex, ey;;
int bfs(){
queue<PII> que;
que.push({sx,sy});
vis[sx][sy] = 1;
while(!que.empty()){
int x = que.front().first, y = que.front().second;
que.pop();
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > n || vis[nx][ny] || g[nx][ny] == '1') continue;
vis[nx][ny] = 1;
que.push({nx,ny});
step[nx][ny] = step[x][y] + 1;
if(nx == ex && ny == ey) return step[nx][ny];
}
}
return -1;
}
int main(){
cin >> n;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin >> g[i][j];
cin >> sx >> sy >> ex >> ey;
cout << bfs() << endl;
return 0;
}
四、Mzc和男家丁的游戏
题目链接:P2298 Mzc和男家丁的游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
mzc家很有钱(开玩笑),他家有n个男家丁(做过上一弹的都知道)。他把她们召集在了一起,他们决定玩捉迷藏。现在mzc要来寻找他的男家丁,大家一起来帮忙啊!
由于男家丁数目不多,再加上mzc大大的找人【laopo】水平很好,所以一次只需要找一个男家丁。
输入格式
第一行有两个数n,m,表示有n行m列供男家丁躲藏,
之后n行m列的矩阵,‘m‘表示mzc,‘d’表示男家丁,‘#’表示不能走,‘.‘表示空地。
输出格式
一行,若有解:输出一个数step,表示找到男家丁的最短移动次数。
若无解:输出“No Way!”。
输入输出样例
输入 #1
5 6
.#..#.
....#.
d.....
#####.
m.....
输出 #1
12
数据范围
3 < = m, n <= 2000
由于mzc大大十分着急,所以他只能等待1S。
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 2e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};
int vis[N][N];
char g[N][N];
int n, m, sx, sy, ex, ey;;
struct Node {
int x, y, step;
Node(int x, int y, int step){
this->x = x;
this->y = y;
this->step = step;
}
};
int bfs(){
queue<Node> que;
que.push(Node(sx, sy, 0));
vis[sx][sy] = 1;
while(!que.empty()){
int x = que.front().x, y = que.front().y, step = que.front().step;
que.pop();
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] || g[nx][ny] == '#') continue;
vis[nx][ny] = 1;
que.push(Node(nx, ny, step + 1));
if(nx == ex && ny == ey) return step + 1;
}
}
return -1;
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
cin >> g[i][j];
if(g[i][j] == 'm') sx = i, sy = j;
if(g[i][j] == 'd') ex = i, ey = j;
}
int ans = bfs();
if(ans == -1) cout<<"No Way!"<<endl;
else cout << ans << endl;
return 0;
}
五、血色先锋队
题目链接:P1332 血色先锋队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
军团是一个 nn 行 mm 列的矩阵,每个单元是一个血色先锋军的成员。感染瘟疫的人,每过一个小时,就会向四周扩散瘟疫,直到所有人全部感染上瘟疫。你已经掌握了感染源的位置,任务是算出血色先锋军的领主们感染瘟疫的时间,并且将它报告给巫妖王,以便对血色先锋军进行一轮有针对性的围剿。
输入格式
第 11 行:四个整数 nn,mm,aa,bb,表示军团矩阵有 nn 行 mm 列。有 aa 个感染源,bb 为血色敢死队中领主的数量。
接下来 aa 行:每行有两个整数 xx,yy,表示感染源在第 xx 行第 yy 列。
接下来 bb 行:每行有两个整数 xx,yy,表示领主的位置在第 xx 行第 yy 列。
输出格式
第 11 至 bb 行:每行一个整数,表示这个领主感染瘟疫的时间,输出顺序与输入顺序一致。如果某个人的位置在感染源,那么他感染瘟疫的时间为 00。
输入输出样例
输入 #1
5 4 2 3
1 1
5 4
3 3
5 3
2 4
输出 #1
3
1
3
说明/提示
输入输出样例 1 解释
如下图,标记出了所有人感染瘟疫的时间以及感染源和领主的位置。
数据规模与约定
对于 100% 的数据,保证 1 ≤ n , m ≤ 500,1 ≤ a , b ≤ 105。
code1
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int inf = 1e9;
const int N = 1e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};
int vis[N][N];
int g[N][N];
int n, m, a, b;
int flag = 1;
void bfs(int sx, int sy){
queue<PII> que;
que.push({sx,sy});
vis[sx][sy] = 1;
int count = 0;
while(!que.empty() && count < 19000){
count++;
int x = que.front().first, y = que.front().second;
que.pop();
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > n || vis[nx][ny] == flag) continue;
vis[nx][ny] = flag;
que.push({nx,ny});
g[nx][ny] = min(g[nx][ny], g[x][y] + 1);
}
}
}
int main(){
cin >> n >> m >> a >> b;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
g[i][j] = inf;
}
}
int tx, ty;
for(int i = 0; i < a; i++){
cin >> tx >> ty;
g[tx][ty] = 0;
bfs(tx, ty);
flag++;//标记此次是否被搜索过
}
for(int i = 0; i < b; i++){
cin >> tx >> ty;
cout << g[tx][ty] << endl;
}
return 0;
}
code2:
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
#define debug cout << "___debug___\n";
using namespace std;
typedef pair<int,int> PII;
const int inf = 1e9;
const int N = 1e3+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};
struct Node {
int x, y, step;
Node(int x, int y, int step){
this->x = x;
this->y = y;
this->step = step;
}
};
int vis[N][N];
int g[N][N];
int n, m, a, b;
int flag = 1;
queue<Node> que;
void init(){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
g[i][j] = inf;
}
}
}
void bfs(){
while(!que.empty()){
int x = que.front().x, y = que.front().y, step = que.front().step;
que.pop();
g[x][y] = min(g[x][y], step);
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny]) continue;
vis[nx][ny] = 1;
que.push(Node(nx, ny, step + 1));
}
}
}
int main(){
cin >> n >> m >> a >> b;
init();
int tx, ty;
for(int i = 0; i < a; i++){
cin >> tx >> ty;
que.push(Node(tx,ty,0));
g[tx][ty] = 0;
vis[tx][ty] = 1;
}
bfs();
for(int i = 0; i < b; i++){
cin >> tx >> ty;
cout << g[tx][ty] << endl;
}
return 0;
}
六、求细胞数量
题目链接:P1451 求细胞数量 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
一矩形阵列由数字 0 到 9 组成,数字 1到 9代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。
输入格式
第一行两个整数代表矩阵大小 n 和 m。
接下来 n 行,每行一个长度为 m 的只含字符 0
到 9
的字符串,代表这个 n×m 的矩阵。
输出格式
一行一个整数代表细胞个数。
输入输出样例
输入 #1
4 10
0234500067
1034560500
2045600671
0000000089
输出 #1
4
说明/提示
数据规模与约定
对于 100% 的数据,保证 1 ≤ n , m ≤ 100。
#include<iostream>
#include<stack>
#include<vector>
#include<string>
#include<cstring>
#include<map>
#include<algorithm>
#include<cmath>
#include<queue>
#define debug cout << "___debug___\n";
using namespace std;
typedef pair<int,int> PII;
const int inf = 1e9;
const int N = 1e2+10;
const int dx[] = {0,1,0,-1};
const int dy[] = {1,0,-1,0};
int vis[N][N];
char g[N][N];
int n, m, ans;
queue<PII> que;
void bfs(int sx, int sy){
ans ++;
que.push({sx,sy});
vis[sx][sy] = 1;
while(!que.empty()){
int x = que.front().first, y = que.front().second;
que.pop();
for(int i = 0; i < 4; i++){
int nx = x + dx[i], ny = y + dy[i];
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] || g[nx][ny] == '0') continue;
vis[nx][ny] = 1;
que.push({nx, ny});
}
}
}
int main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin >> g[i][j];
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if(g[i][j] != '0' && !vis[i][j]) bfs(i, j);//记得判断该细胞是否被访问过,否则会重复很多
}
}
cout << ans << endl;
return 0;
}