2019蓝桥杯校内选拔赛题解

本文精选了算法竞赛中的经典题目,包括迷宫寻宝、数组元素选择、字符串排序、算术表达式优化等,覆盖了BFS、DP、归并排序、DFS等多种算法,为参赛者提供了详细的解题思路与代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目传送

A Perfect

B Common(Easy Version)

详见Common(Easy、Middle 、Hard)

C Common(Hard Version)

详见Common(Easy、Middle 、Hard)

D Treasure

有一个 n 行 m 列的迷宫, 行数从上到下为 1 到 n, 列数从左到右为 1 到 m, 入口为 (1,1),
Reverie只能向上下左右四个方向行走。迷宫中有若干个宝箱。Reverie想知道,最少需要走多少步,才能找到一个宝箱。

第一行两个正整数 n, m, 表示迷宫的行数和列数。
之后 n 行,每行 m 个字符, ‘.’ 表示该位置是空地, ‘*’ 表示该位置是障碍, ‘#’ 表示该位置有一个宝箱。
保证点 (1,1) 是空地,宝箱所在的格子可以通过。
1 ≤ n , m ≤ 1000 1≤n,m≤1000 1n,m1000
一行内输出一个整数表示答案,如果没有宝箱或者所有宝箱位置均不可达,输出 -1.

BFS

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mp make_pair
#define pb push_back
ll gcd(ll a,ll b) { return !b?a:gcd(b,a%b);}
ll lcm(ll a,ll b){ return a/gcd(a,b)*b;}
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int cnt = 0;
int r[1000+5][1000+5];
bool visited[1000+5][1000+5];
int res[1000+5][1000+5];
bool bfs(int i,int j){
	queue<pair<int,int > > q;
	q.push(mp(i,j));visited[i][j] = 1;
	pair<int,int> t;
	while(!q.empty()){
		t = q.front();
		i = t.first; j = t.second;
		q.pop();
		for(int k=0;k<4;k++){
			int cx = i+dx[k],cy = j+dy[k];
			if(r[cx][cy]&&!visited[cx][cy]){
				cnt = res[i][j]+1;
				res[cx][cy] = cnt;
				visited[cx][cy]=1;
				if(r[cx][cy]==2) return true;
				else q.push(mp(cx,cy));
			}
		}
	}
	return false;
}
int main(){
	int n,m;
	cin >> n >> m;
	memset(visited,0,sizeof(visited));
	memset(r,0,sizeof(r));
	char c;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			cin >> c;
			if(c=='.') r[i][j] = 1;
			else if(c=='#') r[i][j] = 2;
		}		
	
	if(bfs(1,1)) cout << cnt << endl;
	else cout << "-1" << endl;
	return 0;
} 

E Select

R e v e r i e 有 一 个 长 度 为 n 的 正 整 数 数 组 A , 她 想 从 中 挑 出 一 些 数 字 , Reverie有一个长度为 n 的正整数数组 A, 她想从中挑出一些数字, ReverienA,
使 得 这 些 数 字 的 和 最 大 , 选 中 的 任 意 两 个 数 字 在 原 数 组 中 不 能 相 邻 。 使得这些数字的和最大,选中的任意两个数字在原数组中不能相邻。 使

第 一 行 一 个 正 整 数 T , 代 表 测 试 的 组 数 。 第一行一个正整数 T, 代表测试的组数。 T,
每 组 测 试 第 一 行 一 个 正 整 数 n 表 示 数 组 的 大 小 , 第 二 行 n 个 正 整 数 表 示 数 组 里 的 数 , 以 空 格 分 隔 。 每组测试第一行一个正整数 n 表示数组的大小,第二行 n 个正整数表示数组里的数,以空格分隔。 nn
1 ≤ T ≤ 100 1≤T≤100 1T100
1 ≤ n ≤ 1000 1≤n≤1000 1n1000
1 ≤ A i ≤ 1000 1≤A_i≤1000 1Ai1000

状态转移方程:
d p [ 0 ] = a [ 0 ] , d p [ 1 ] = m a x ( a [ 0 ] , a [ 1 ] ) dp[0]=a[0],dp[1]=max(a[0],a[1]) dp[0]=a[0],dp[1]=max(a[0],a[1])
d p [ i ] = m a x ( d p [ i − 1 ] , d p [ i − 2 ] + a [ i ] ) dp[i]=max(dp[i-1],dp[i-2]+a[i]) dp[i]=max(dp[i1],dp[i2]+a[i])

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
	int T;
	cin >> T;
	while(T--){
		int n;
		cin >> n;
		int a[n],dp[n+2];
		memset(dp,0,sizeof(dp));
		for(int i=0;i<n;i++)
			cin >> a[i];
		dp[0] = a[0];
		dp[1] = max(a[0],a[1]);
		for(int i=2;i<n;i++)
			dp[i] = max(dp[i-2]+a[i],dp[i-1]);
		cout << dp[n-1] << endl;
	} 
	return 0;
} 

F Swap(Easy Vesion)

R e v e r i e 有 一 个 字 符 串 , 她 每 次 操 作 可 以 交 换 其 中 任 意 相 邻 两 个 字 符 的 位 置 。 Reverie有一个字符串,她每次操作可以交换其中任意相邻两个字符的位置。 Reverie
R e v e i r e 想 知 道 , 把 这 个 字 符 串 变 成 字 典 序 最 小 至 少 需 要 多 少 次 操 作 。 Reveire想知道,把这个字符串变成字典序最小至少需要多少次操作。 Reveire
第 一 行 一 个 正 整 数 T , 代 表 测 试 的 组 数 。 第一行一个正整数 T, 代表测试的组数。 T,
每 组 测 试 , 一 行 内 给 出 一 个 仅 包 含 小 写 字 母 的 字 符 串 s 。 每组测试,一行内给出一个仅包含小写字母的字符串 s。 s
1 ≤ T ≤ 10 1≤T≤10 1T10
1 ≤ ∣ s ∣ ≤ 1000 1≤∣s∣≤1000 1s1000

最小交换次数即逆序对数
下面使用两重循环暴力求解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll res = 0 ; 
char a[1000005];
int main(){
	int t;
	cin >> t;
	getchar();
	while(t--){
		res = 0;
		scanf("%s",a);
		int n = strlen(a); 
		for(int i=0;i<n;i++){
			for(int j=0;j<i;j++){
				if(a[j]>a[i]){
					res ++;
				}
			}
		}
		cout << res << endl;
	}
	return 0;
} 

G Swap(Hard Vesion)

数据范围改变
1 ≤ T ≤ 10 1≤T≤10 1T10
1 ≤ ∣ s ∣ ≤ 100000 1≤∣s∣≤100000 1s100000
暴力不可行,会超时,使用归并排序求逆序对数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
/*
	归并排序求逆序对 
*/ 

ll res = 0 ; 
char a[1000005];
char b[1000005];
void merge(char a[],int low,int mid,int high){
	int i = low,j = mid +1,k = 0;
	while(i<=mid&&j<=high){
		if((a[i]-'a')<=(a[j]-'a'))	b[k++] = a[i++];
		else {
			b[k++] = a[j++];
			res += (mid-i+1);  // 是mid-i+1 而非j-i 
		}
	}
	while(i<=mid){
		b[k++] = a[i++];
	}
	while(j<=high){
		b[k++] = a[j++];
	}
	k = 0;
	for(i=low;i<=high;i++,k++){
		a[i] = b[k];
	}	
}
void merge_sort(char a[],int low, int high){
	int mid;
	if(low < high){
		mid = (low+high)/2;
		merge_sort(a,low,mid);
		merge_sort(a,mid+1,high);
		merge(a,low,mid,high);
	}
}


int main(){
	int t;
	cin >> t;
	getchar();
	while(t--){
		res = 0;
		scanf("%s",a); 
		merge_sort(a,0,strlen(a)-1);
		cout << res << endl;
	}
	return 0;
} 

H Operator

R e v e r i e 有 一 个 长 度 为 n 的 整 数 数 组 A , 她 想 在 每 两 个 数 之 间 填 入 Reverie有一个长度为n的整数数组A,她想在每两个数之间填入 ReverienA
‘ + ’ 或 者 ‘ − ’ , 使 得 最 终 运 算 结 果 尽 可 能 接 近 给 定 的 评 估 值 k . ‘+’ 或者 ‘-’, 使得最终运算结果尽可能接近给定的评估值 k. +,使k.

I n p u t Input Input
第 一 行 一 个 正 整 数 T , 代 表 测 试 的 组 数 。 第一行一个正整数 T, 代表测试的组数。 T,
每 组 测 试 , 第 一 行 两 个 整 数 n , k 分 别 表 示 数 组 的 大 小 和 给 定 的 评 估 值 , 每组测试,第一行两个整数 n, k 分别表示数组的大小和给定的评估值, n,k
第 二 行 n 个 正 整 数 表 示 数 组 里 的 数 , 以 空 格 分 隔 。 第二行 n 个正整数表示数组里的数,以空格分隔。 n

1 ≤ T ≤ 10 1≤T≤10 1T10
2 ≤ n ≤ 20 2≤n≤20 2n20
1 ≤ k , A i ≤ 1 0 6 1≤k,A_i≤10^6 1k,Ai106

O u t p u t Output Output
每 组 测 试 , 一 行 内 输 出 一 个 整 数 表 示 运 算 结 果 与 k 的 差 值 的 绝 对 值 的 最 小 值 。 每组测试,一行内输出一个整数表示运算结果与 k 的差值的绝对值的最小值。 k

S a m p l e I n p u t Sample Input SampleInput

2
3 7
3 6 9
4 6
1 2 3 4

S a m p l e O u t p u t Sample Output SampleOutput

1
0

DFS即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll inf = 0x3f3f3f3f;
const int maxn = 200;
char best[maxn];
void dfs(int a[],int n,int sum,int i,char op[],int tar){
	if(i==n){
		if(abs(sum-tar)<abs(inf-tar)){
			inf = sum;
			for(int i=1;i<n;i++)
				best[i] = op[i];	
		}
		return ;
	}
	sum += a[i];
	op[i] = '+';
	dfs(a,n,sum,i+1,op,tar);
	sum -= a[i];
	
	sum -= a[i];
	op[i] = '-';
	dfs(a,n,sum,i+1,op,tar);
	sum += a[i];
} 
int main(){
	int t;
	cin >> t;
	getchar();
	while(t--){
		int n; cin >> n;
		ll tar; cin >> tar;
		int a[n];
		for(int i=0;i<n;i++)
			cin >> a[i];
		char op[n];
		dfs(a,n,a[0],1,op,tar);
		ll res = a[0];
		for(int i=1;i<n;i++){
			if(best[i]=='+')
				res += a[i];
			else if(best[i]=='-')
				res -= a[i];
		}
		cout << abs(res-tar) << endl;
		inf = 0x3f3f3f3f;  // 记得修改inf的值 
	}
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值