蓝桥杯之搜索专题

ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while (t--) {
    solve();
}
return 0;

}


### T4:[穿越雷区]( )(16年蓝桥杯国赛)



> 
> #### 解题思路
> 
> 
> **特点是要交替走网格,就可以以此来剪枝,虽然是国赛,但是很简单,注意起点和终点的状态**
> 
> 
> 


#### **代码**



#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;
using pii = pair<int,int>;

int n;
pii a,b; // A/B
char g[105][105]; // 存图
int st[105][105];
int ans = 1e9;
int dx[] = {0,0,0,-1,1};
int dy[] = {0,1,-1,0,0};
// 当前点,步数,以及上一个点的状态
void dfs(int x, int y, int cnt, char status) {
if (x == b.f && y == b.s) { // 合法答案
ans = min(ans, cnt);
return ;
}

for (int i = 1;i <= 4; i++) {
	int nx = x + dx[i];
	int ny = y + dy[i];
	if (nx<=0||nx>n||ny<=0||ny>n||st[nx][ny]) continue;
	if (g[x][y]!='A' && status == g[nx][ny]) continue;
	st[nx][ny] = 1;
	dfs(nx,ny,cnt+1,g[nx][ny]);
	st[nx][ny] = 0;
}

}
void solve() {
cin >> n;
for (int i = 1;i <= n; i++) {
for (int j = 1;j <= n; j++) {
cin >> g[i][j];
if (g[i][j] == ‘A’) a = {i,j};
if (g[i][j] == ‘B’) b = {i,j};
}
}
dfs(a.f, a.s, 0, 1);
ans = (ans == 1e9?-1:ans);
cout << ans;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while (t–) {
solve();
}
return 0;
}


### T5: [飞机降落]( )(23年蓝桥杯省赛)



> 
> #### 解题思路:
> 
> 
> **DFS飞机降落的顺序**
> 
> 
> **剪枝策略:当有飞机无法降落时回溯**
> 
> 
> 


#### **代码:**



// DFS
#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

const int N = 1e5 + 50;
struct node {
int t; // 最早降落时间
int d; // 周旋时间
int l; // 降落花费的时间
}a[20];
int n;
string ans;
bool st[N]; // 标记当前飞机是否降落
// 已经降落了几架飞机以及上一架飞机降落的时间
void dfs(int u,int last) {
if (u >= n) { // 飞机全部安全降落,递归退出点
ans = “YES”;
return ;
}
for (int i = 1;i <= n; i++) {
if (st[i]) continue;
// 1.判断当前飞机是否可以降落
if (a[i].t + a[i].d < last) return ; // 不能降落,回溯
// 2.思考u+1个位置由谁降落
st[i] = true;
dfs(u + 1,max(a[i].t,last) + a[i].l);
st[i] = false;
}
}
void solve() {
cin >> n; // 飞机架数
for (int i = 1;i <= n; i++) st[i] = false; // 初始化st数组
for (int i = 1;i <= n; i++) {
cin >> a[i].t >> a[i].d >> a[i].l;
}
ans = “NO”;
dfs(0,0);
cout << ans << ‘\n’;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t; cin >> t;
while (t–) {
solve();
}
return 0;
}


### T6:[卡片换位]( )(16年蓝桥杯省赛)



> 
> #### 解题思路:DFS
> 
> 
> **交换可以看成移动空格,手动模拟一下就会发现,最多17就一定能实现交换,我们枚举交换的次数0~17,然后对于每一个答案做dfs,能满足条件的第一个答案即为最小值;**
> 
> 
> **但是DFS不是正解,正解是BFS**
> 
> 
> 


#### **代码**



// DFS遍历
#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;
using pii = pair<int,int>;

const int N = 5;
char g[N][N];
pii a,b,k;
int sum = 0;
int num = -1;
int dx[] = {0,0,0,-1,1};
int dy[] = {0,1,-1,0,0};
void dfs(int x,int y,int cnt) {
if (g[a.f][a.s] == ‘B’ && g[b.f][b.s] == ‘A’) { // 目标状态
num = cnt;
return ;
}
if (cnt > sum) return ;
for (int i = 1;i <= 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx<0||nx>=2||ny<0||ny>=3) continue;
swap(g[x][y], g[nx][ny]); // 交换
dfs(nx, ny, cnt+1);
swap(g[x][y], g[nx][ny]); // 回溯
}

}
void solve() {
for (int i = 0;i < 2; i++) {
string s1; getline(cin, s1);
for (int j = 0;j < 3; j++) g[i][j] = s1[j];
}
for (int i = 0;i < 2; i++) {
for (int j = 0;j < 3; j++) {
if (g[i][j] == ‘A’) a = {i,j}; // A的位置
if (g[i][j] == ‘B’) b = {i,j}; // B的位置
if (g[i][j] == ’ ') k = {i,j}; // 空格的位置
}
}

for (int i = 1;i <= 20; i++) { // 枚举次数
	sum = i;
	dfs(k.f,k.s,0);
	if (num != -1) {
		cout << num;
		return ;
	}
}

}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while (t–) {
solve();
}
return 0;
}


## BFS



> 
> **写了好多BFS的题,最重要的一点就是判重,写的好几个题都是通过二维转一维,即将图转化成字符串来保存状态,使用map/set来标记判重**
> 
> 
> 


### **T1:[青蛙跳杯子]( )**



> 
> #### 解题思路
> 
> 
> **我们用BFS遍历青蛙跳杯子的所有状态,定义map<string,int> 来标记每个状态,去掉重复的状态,当到达目标状态时的步数即为答案;**
> 
> 
> 
> **注意:每次遍历都有一个找空杯子的过程,我们可以用string的find函数来快速找到空杯子的位置;**
> 
> 
> 


#### **代码**



// BFS搜索,map去重,注意状态要还原
#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

const int N = 1e5 + 50;
string s,e;
int n;
unordered_map<string, int> ump;
int dx[] = {0,-3,-2,-1,1,2,3};// 向左右跳的6种情况
queue q;
void bfs() {
// 初始化
q.push(s);
ump[s] = 0;
while (q.size()) {
string now = q.front(); q.pop(); // 当前串
int cnt = ump[now]; // 当前次数
if (now == e) { // 合法答案
cout << cnt;
return ;
}
int k = now.find(‘*’); // 空杯子的位置
for (int i = 1;i <= 6; i++) { // 枚举6个位置
int nk = k + dx[i];
if (nk < 0 || nk >= n) continue;
swap(now[nk], now[k]); // 移动
if (!ump[now]) {
ump[now] = cnt + 1;
q.push(now); // 当前是一个新状态
}
swap(now[nk], now[k]); // 还原
}
}
}
void solve() {
cin >> s;
cin >> e;
n = s.size();
bfs();
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while (t–) {
solve();
}
return 0;
}


### **T2:[卡片换位]( )**(16年蓝桥杯省赛)



> 
> #### 解题思路:BFS
> 
> 
> **该题可以说是上一题的二维版本,但是我们任然使用一维字符串来存状态,就需要一维和二维的转换;**
> 
> 
> * **二维转一维:直接将每一行拼接即可**
> * **一维转二维:除法和取模**
> 
> 
> **BFS搜索空格的交换方案,并用字符串记录当前方案的状态,遇到的第一个合法答案就是最小步数(因为BFS有最短路性质),map即标记了当前状态,又保存当前状态与步数之间的关系;**
> 
> 
> 



> 
> **注意:**
> 
> 
> 1. **使用unordered\_map比map效率更高**
> 2. **注意要使用getline读入带空格的字符串**
> 
> 
> 


#### 代码



#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

int dx[] = {0,0,0,-1,1};
int dy[] = {0,1,-1,0,0};
unordered_map<string, int> ump; // 存状态与步数的关系
queue q;
string s;
int a,b; // 存A/B的下标
void bfs() {
q.push(s);
ump[s] = 0;

while (q.size()) {
	auto now = q.front(); q.pop(); // 当前状态
	int cnt = ump[now]; // 当前步数
	if ((int)now.find('A')==b && (int)now.find('B')==a) { // 交换成功
		cout << cnt;
		return ;
	}
	int pos = now.find(" "); // 找空格的位置
	int x = pos/3, y = pos%3; // 转二维
	
	for (int i = 1;i <= 4; i++) {
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (nx<0||nx>=2||ny<0||ny>=3) continue;
		swap(now[pos], now[nx*3+ny]); // 交换
		if (!ump[now]) { // 当前是新状态
			ump[now] = cnt + 1; // 标记
			q.push(now);
		}
	    swap(now[pos], now[nx*3+ny]); // 还原
	}
}

}
void solve() {
for (int i = 1;i <= 2; i++) {
string t;
getline(cin, t); // 带空格的字符串的读入方式
s += t;
}
a = s.find(‘A’);
b = s.find(‘B’);
bfs();
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
while (t–) {
solve();
}
return 0;
}


###  T3:[九宫重排]( )(13年蓝桥杯国赛)



> 
> #### 解题思路
> 
> 
> **该题是卡片换位的升级版,由2\*3变成了3\*3,思路几乎一摸一样,不做讲解**
> 
> 
> 


#### **代码**



#include <bits/stdc++.h>
#define int long long
#define f first
#define s second
#define all(x) x.begin(),x.end()
using namespace std;

const int N = 1e5 + 50;
string s,e;
unordered_map<string, int> ump;
queue q;
int dx[] = {0,0,0,-1,1};
int dy[] = {0,1,-1,0,0};

int bfs(string s, int cnt) {
// 初始化
q.push(s);
ump[s] = cnt;
while (q.size()) {

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值