蓝桥杯练习题——搜索

1.八皇后 Checker Challenge

题目链接
注意数组空间要开大点,防止对角线数组存不下

#include<iostream>
#include<cstring>
using namespace std;
const int N = 50;
int a[N];
int st1[N], st2[N], st3[N];
int n, cnt;

// 行数 
void dfs(int u){
	if(u > n){
		cnt++;
		if(cnt <= 3){
			for(int i = 1; i <= n; i++) printf("%d ", a[i]);
			printf("\n");
		}
		return;
	}
	for(int i = 1; i <= n; i++){
		if(!st1[i] && !st2[u + i] && !st3[n - u + i]){
			st1[i] = 1;
			st2[u + i] = 1;
			st3[n - u + i] = 1;
			a[u] = i;
			dfs(u + 1);
			st1[i] = 0;
			st2[u + i] = 0;
			st3[n - u + i] = 0;
		}
	}
}

int main(){
	scanf("%d", &n);
	dfs(1);
	printf("%d", cnt);
	return 0;
}

2.kkksc03考前临时抱佛脚

指数型枚举每道题交给哪个脑子解决

#include<iostream>
#include<cstring>
using namespace std;
const int N = 50;
int a[N][N], b[N];
int l, r;
int res, ans;

void dfs(int pos, int u){
	if(u > b[pos]){
		res = min(res, max(l, r));
		return;
	}
	
	l += a[pos][u];
	dfs(pos, u + 1);
	l -= a[pos][u];
	
	r += a[pos][u];
	dfs(pos, u + 1);
	r -= a[pos][u];
}

int main(){
	for(int i = 1; i <= 4; i++) scanf("%d", &b[i]);
	for(int i = 1; i <= 4; i++){
		l = 0, r = 0, res = 1e9;
		for(int j = 1; j <= b[i]; j++){
			scanf("%d", &a[i][j]);
		}
		dfs(i, 0);
		ans += res;
	}
	printf("%d", ans);
	return 0;
}

01 背包,一个物品只会被用一次,求一半容量背包最多能装多少物品,然后最短花费时间就是总容量减去一半容量最多能装的物品,sum - f[sum / 2]

#include<iostream>
#include<cstring>
using namespace std;
const int N = 50;
int a[N], b[N];
int f[1500];
int ans;

int main(){
	for(int i = 1; i <= 4; i++) scanf("%d", &b[i]);
	for(int i = 1; i <= 4; i++){
		int sum = 0;
		memset(f, 0, sizeof(f));
		for(int j = 1; j <= b[i]; j++){
			scanf("%d", &a[j]);
			sum += a[j];
		}
		for(int ii = 1; ii <= b[i]; ii++){
			for(int jj = sum / 2; jj >= a[ii]; jj--){
				f[jj] = max(f[jj], f[jj - a[ii]] + a[ii]);
			}
		}
		ans += sum - f[sum / 2];
	}
	printf("%d", ans);
	return 0;
}

3.马的遍历

注意是 it.first 和 it.second 操作,不要用成 x 和 y 了

#include<iostream>
#include<cstring>
using namespace std;
const int N = 500;
int g[N][N], st[N][N];
pair<int, int> q[N * N];
int hh = 0, tt = -1;
int n, m;

int dx[] = {-2, -1, 1, 2, 2, 1, -1, -2};
int dy[] = {1, 2, 2, 1, -1, -2, -2, -1};

void bfs(int x, int y){
	q[++tt] = {x, y};
	st[x][y] = 0;
	while(hh <= tt){
		auto it = q[hh++];
		for(int i = 0; i < 8; i++){
			int a = it.first + dx[i], b = it.second + dy[i];
			if(a < 1 || a > n || b < 1 || b > m) continue;
			if(st[a][b] >= 0) continue;
			st[a][b] = st[it.first][it.second] + 1;
			q[++tt] = {a, b};
		}
	}
}

int main(){
	memset(st, -1, sizeof(st));
	int x, y;
	scanf("%d%d%d%d", &n, &m, &x, &y);
	bfs(x, y);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			printf("%d ", st[i][j]);
		}
		printf("\n");
	}
	return 0;
}

4.奇怪的电梯

#include<iostream>
#include<cstring>
using namespace std;
const int N = 300;
int q[N], st[N];
int hh = 0, tt = -1;
int c[N];
int n, A, B;

void bfs(int x){
	q[++tt] = x;
	st[x] = 0;
	while(hh <= tt){
		int it = q[hh++];
		//cout<<it<<endl;
		int a = it + c[it], b = it - c[it];
		if(a <= n && st[a] == -1){
			st[a] = st[it] + 1;
			if(a == B) return;
			q[++tt] = a;
		}
		if(b >= 1 && st[b] == -1){
			st[b] = st[it] + 1;
			if(b == B) return;
			q[++tt] = b;
		}
	}
}

int main(){
	memset(st, -1, sizeof(st));
	int x, y;
	scanf("%d%d%d", &n, &A, &B);
	for(int i = 1; i <= n; i++) scanf("%d", &c[i]);
	bfs(A);
	printf("%d", st[B]);
	return 0;
}

5.Meteor Shower S(难)

结构体存储坐标、时间、步数、判重

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1005;
int ans = -1;
struct Point{
	int x, y, t, step, vis;
}g[N][N];

int dx[] = {0, 0, -1, 1, 0};
int dy[] = {-1, 1, 0, 0, 0};

void bfs(int x, int y){
	queue<Point> q;
	g[x][y].vis = 1;
	g[x][y].step = 0;
	q.push(g[x][y]);
	while(q.size()){
		auto it = q.front();
		q.pop();
		for(int i = 0; i < 4; i++){
			int a = it.x + dx[i], b = it.y + dy[i];
			if(a < 0 || b < 0 || g[a][b].vis == 1) continue;
			if(g[a][b].t == -1){
				ans = it.step + 1;
				return;
			}
			if(it.step >= g[a][b].t - 1) continue;
			g[a][b].vis = 1;
			g[a][b].step = it.step + 1;
			q.push(g[a][b]);
		}
	}
}

int main(){
	memset(g, -1, sizeof(g));
	int m, x, y, t;
	scanf("%d", &m);
	for(int i = 0; i <= 1000; i++){
		for(int j = 0; j <= 1000; j++){
			g[i][j].x = i;
			g[i][j].y = j;
		}
	}
	for(int i = 1; i <= m; i++){
		scanf("%d%d%d", &x, &y, &t);
		for(int j = 0; j < 5; j++){
			int a = x + dx[j], b = y + dy[j];
			if(a >= 0 && b >= 0 && (g[a][b].t == -1 || g[a][b].t > t)) g[a][b].t = t;
		}
	}
	bfs(0, 0);
	printf("%d", ans);
	return 0;
}

6.选数

#include<iostream>
using namespace std;
const int N = 5e6 + 10;
int a[N], b[N];
int n, k;
int cnt;

int check(int x){
	if(x < 2) return 0;
	for(int i = 2; i <= x / i; i++){
		if(x % i == 0) return 0;
	}
	return 1;
}

void dfs(int u, int st){
	if(u > k){
		int sum = 0;
		for(int i = 1; i < u; i++) sum += b[i];
		if(check(sum)) cnt++;
		return;
	}
	for(int i = st; i <= n; i++){
		b[u] = a[i];
		dfs(u + 1, i + 1);
	}
}

int main(){
	scanf("%d%d", &n, &k);	
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	dfs(1, 1);
	printf("%d", cnt);
	return 0;
}

7.PERKET

#include<iostream>
using namespace std;
const int N = 20;
int s[N], b[N], st[N];
int n, ans = 1e9;

void dfs(int u){
	if(u > n){
		int res1 = 1, res2 = 0;
		for(int i = 1; i <= n; i++){
			if(st[i]){
				res1 *= s[i];
				res2 += b[i];
			}
		}
		if(res1 == 1 && res2 == 0) return;
		ans = min(ans, abs(res1 - res2));
		return;
	}
	// 不选
	st[u] = 0;
	dfs(u + 1);
	st[u] = 0;
	
	// 选
	st[u] = 1;
	dfs(u + 1);
	st[u] = 0; 
}

int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d%d", &s[i], &b[i]);
	dfs(0);
	printf("%d", ans);
	return 0;
}

8.吃奶酪(难)

dfs 维护四个数据,当前的点、一共走了多少个点、走过的点二进制表示、走过的总距离
结构体 Point 维护四个数据,x 和 y 的坐标,走没走过,这个坐标是几号点
二维数组 f 维护两个数据,已经走过的点,二进制表示

#include<iostream>
#include<cmath>
using namespace std;
const int N = 1 << 15;
double f[16][N + 10];
struct Point{
	double x, y;
	int vis, num;
}p[16];
int n;
double ans = 1e9;

double dis(Point p1, Point p2){
	double sum = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
	return sum;
}

void dfs(Point p1, int cnt, int mk, double sum){
    if(sum > ans) return;
	if(cnt == n){
		ans = sum;
		return;
	}
	for(int i = 0; i < n; i++){
		if(p[i].vis) continue;
		int t = mk + (1 << i);
		if(!f[i][t] || f[i][t] > f[p1.num][mk] + dis(p1, p[i])){
			f[i][t] = f[p1.num][mk] + dis(p1, p[i]);
			p[i].vis = 1;
			dfs(p[i], cnt + 1, t, sum + dis(p1, p[i]));
			p[i].vis = 0;
		}
	}
}

int main(){
	cin>>n;
	double x, y;
	for(int i = 0; i < n; i++){
		cin>>x>>y;
		p[i] = {x, y, 0, i};
	}
	Point p0 = {0, 0, 1, 0};
	dfs(p0, 0, 0, 0);
	printf("%.2lf", ans);
	return 0;
}

9.迷宫

把上一个点打上标记,然后回溯

#include<iostream>
using namespace std;
const int N = 10;
int g[N][N], vis[N][N];
int n, m, t;
int sx, sy, fx, fy;
int cnt;

int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};

void dfs(int x, int y){
	if(x == fx && y == fy){
		cnt++;
		return;
	}
	for(int i = 0; i < 4; i++){
		int a = x + dx[i], b = y + dy[i];
		if(a < 1 || a > n || b < 1 || b > m) continue;
		if(g[a][b] == 1) continue;
		if(vis[a][b] == 1) continue;
		vis[x][y] = 1;
		dfs(a, b);
		vis[x][y] = 0;
	}
}

int main(){
	cin>>n>>m>>t;
	cin>>sx>>sy>>fx>>fy;
	int x, y;
	for(int i = 1; i <= t; i++){
		cin>>x>>y;
		g[x][y] = 1;
	}
	dfs(sx, sy);
	cout<<cnt;
	return 0;
}

10.单词接龙(难)

dfs 维护当前已经接完龙的字符串

#include<iostream>
#include<map>
using namespace std;
const int N = 25;
string s[N];
map<string, int> mp;
int n;
int ans;

string check(string s1, string s2){
	int n1 = s1.size(), n2 = s2.size();
	for(int len = 1; len < n1 && len < n2; len++){
		if(s1.substr(n1 - len) == s2.substr(0, len)){
			string t = s1 + s2.substr(len);
			return t;
		}
	} 
	return "加训";
}

void dfs(string ss){
	if(ss.size() > ans) ans = ss.size();
	for(int i = 1; i <= n; i++){
		if(mp[s[i]] == 2) continue;
		string t = check(ss, s[i]);
		if(t != "加训"){
			mp[s[i]]++;
			dfs(t);
			mp[s[i]]--; 
		}
	}
}

int main(){
	cin>>n;
	for(int i = 1; i <= n; i++){
		cin>>s[i];
	}
	char st;
	cin>>st;
	for(int i = 1; i <= n; i++){
		if(s[i][0] == st){
			mp[s[i]]++;
			dfs(s[i]);
			mp[s[i]]--;
		}
	}
	cout<<ans;
	return 0;
}

11.单词方阵(难)

dfs 维护五个数据,当前坐标,下次要搜索的方向,已经搜索的个数

#include<iostream>
using namespace std;
const int N = 110;
char g[N][N], ans[] = " yizhong";
int s[N][N];
int n;

int dx[] = {0, 0, -1, 1, -1, -1, 1, 1};
int dy[] = {-1, 1, 0, 0, -1, 1, -1, 1};

// xx 和 yy 是搜索方向 
int dfs(int x, int y, int xx, int yy, int cnt){
	if(cnt == 8){
		return 1;
	}
	if(g[x][y] == ans[cnt]){
		if(dfs(x + xx, y + yy, xx, yy, cnt + 1)){
			s[x][y] = 1;
			return 1;
		}
	}
	return 0;
}

int main(){
	cin>>n;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			cin>>g[i][j];
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(g[i][j] == 'y'){
				for(int k = 0; k < 8; k++){
					int a = i + dx[k], b = j + dy[k];
					if(a < 1 || a > n || b < 1 || b > n) continue;
					if(g[a][b] == 'i'){
						dfs(i, j, dx[k], dy[k], 1);
					}
				}
			}
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			if(s[i][j]) cout<<g[i][j];
			else cout<<'*';
		}
		cout<<endl;
	}
	return 0;
}

12.自然数的拆分问题

dfs 维护三个数据,当前第几个数,还需要拆分的数,下次拆分起始数

#include<iostream>
#include<map>
using namespace std;
const int N = 10;
int a[N];

void dfs(int u, int n, int st){
	if(n == 0){
		if(u <= 2) return;
		for(int i = 1; i < u; i++){
			if(i != u - 1) cout<<a[i]<<'+';
			else cout<<a[i];
		}
		cout<<endl;
		return;
	}
	for(int i = st; i <= n; i++){
		a[u] = i;
		dfs(u + 1, n - i, i);
	}
}

int main(){
	int n;
	cin>>n;
	dfs(1, n, 1);
	return 0;
}

13.Lake Counting S

#include<iostream>
using namespace std;
const int N = 110;
char g[N][N];
int vis[N][N];
int n, m;

int dx[] = {0, 0, -1, 1, 1, 1, -1, -1};
int dy[] = {-1, 1, 0, 0, -1, 1, -1, 1};

void dfs(int x, int y){
	vis[x][y] = 1;
	for(int i = 0; i < 8; i++){
		int a = x + dx[i], b = y + dy[i];
		if(a < 1 || a > n || b < 1 || b > m) continue;
		if(vis[a][b]) continue;
		if(g[a][b] != 'W') continue;
		dfs(a, b);
	}
}

int main(){
	cin>>n>>m;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			cin>>g[i][j];
		}
	}
	int res = 0;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(g[i][j] == 'W' && !vis[i][j]){
				res++;
				dfs(i, j);
			}
		}
	}
	cout<<res;
	return 0;
}

14.填涂颜色

#include<iostream>
using namespace std;
const int N = 110;
int g[N][N];
int vis[N][N];
int n, m;

int dx[] = {0, 0, -1, 1, 1, 1, -1, -1};
int dy[] = {-1, 1, 0, 0, -1, 1, -1, 1};

void dfs(int x, int y){
	vis[x][y] = 1;
	for(int i = 0; i < 4; i++){
		int a = x + dx[i], b = y + dy[i];
		if(a < 0 || a > n + 1 || b < 0 || b > n + 1) continue;
		if(vis[a][b]) continue;
		if(g[a][b] != 0) continue;
		dfs(a, b);
	}
}

int main(){
	cin>>n;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			cin>>g[i][j];
		}
	}
	dfs(0, 0);
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			//cout<<vis[i][j]<<" ";
			if(vis[i][j] == 1 || g[i][j] == 1) cout<<g[i][j]<<" ";
			else cout<<2<<" ";
		}
		cout<<endl;
	}
	return 0;
}

15.字符变换(难)

学会用 substr 和 replace 两个函数
bfs 队列里维护两个数据,当前字符串,已经操作的步数

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
string a[10], b[10];
string st, ed;
int n;
struct Point{
	string s;
	int sum;
};

int bfs(){
	queue<Point> q;
	q.push({st, 0});
	while(q.size()){
		auto it = q.front();
		q.pop();
		if(it.sum == 10) continue;
		for(int i = 0; i < n; i++){
			int x = it.s.find(a[i]);
			while(x != -1){
				string t = it.s;
				t.replace(x, a[i].size(), b[i]);
				if(t == ed){
					return it.sum + 1;
				}
				q.push({t, it.sum + 1});
				x = it.s.find(a[i], x + 1);
			}
		}
	}
	return 1e9;
}

int main(){
	cin>>st>>ed;
	while(cin>>a[n]>>b[n]){
	    n++;
		//cout<<"还需要加训!"<<endl;
	}
	//cout<<n<<endl;
	int ans = bfs();
	if(ans == 1e9) cout<<"NO ANSWER!";
	else cout<<ans;
	return 0;
}

16.Corn Maze S(难)

可以重复传送一次

#include<iostream>
#include<queue>
using namespace std;
const int N = 310;
char g[N][N];
int vis[N][N];
int n, m;
int sx, sy, ex, ey;
struct Point{
	int x, y;
	int sum;
};

int dx[] = {0, 0, -1, 1};
int dy[] = {-1, 1, 0, 0};

int bfs(int x, int y){
	queue<Point> q;
	vis[x][y] = 1;
	q.push({x, y, 0});
	while(q.size()){
		auto it = q.front();
		//cout<<it.x<<" "<<it.y<<endl;
		q.pop();
		if(g[it.x][it.y] >= 'A' && g[it.x][it.y] <= 'Z'){
			int ok = 0;
			for(int i = 1; i <= n; i++){
				if(ok) break;
				for(int j = 1; j <= m; j++){
					if(g[i][j] == g[it.x][it.y] && !(it.x == i && it.y == j)){
						it.x = i, it.y = j;
						ok = 1;
						break;
					}
				} 
			}
		}
		for(int i = 0; i < 4; i++){
			int a = it.x + dx[i], b = it.y + dy[i], c = it.sum;
			if(a < 1 || a > n || b < 1 || b > m) continue;
			if(g[a][b] == '#') continue;
			if(vis[a][b]) continue;
			if(a == ex && b == ey) return c + 1;
			vis[a][b] = 1;
			q.push({a, b, c + 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];
		}
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			if(g[i][j] == '@'){
				sx = i, sy = j;
			}
			if(g[i][j] == '='){
				ex = i, ey = j;
			}
		}
	}
	//printf("起点:%d %d\n", sx, sy);
	//printf("终点:%d %d\n", ex, ey);
	int ans = bfs(sx, sy);
	cout<<ans;
	return 0;
} 
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值