2019蓝桥杯校内选拔赛题解

题目传送

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
一行内输出一个整数表示答案,如果没有宝箱或者所有宝箱位置均不可达,输出 -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, 她想从中挑出一些数字,
使 使得这些数字的和最大,选中的任意两个数字在原数组中不能相邻。

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

状态转移方程:
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])
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])

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

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

#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
1 s 100000 1≤∣s∣≤100000
暴力不可行,会超时,使用归并排序求逆序对数

#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,她想在每两个数之间填入
+ , 使 k . ‘+’ 或者 ‘-’, 使得最终运算结果尽可能接近给定的评估值 k.

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

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

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

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

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

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;
} 
发布了63 篇原创文章 · 获赞 34 · 访问量 6559

猜你喜欢

转载自blog.csdn.net/SinclairWang/article/details/103432053
今日推荐