蓝桥杯算法入门_24 (2019+2013年真题)

2019

1.组队(可以直接看)
或打表遍历,按ans最大更新 ,相等时可以 if(j == i)continue 跳过
2.年号字串 26进制 可以excel表 、 计算器 、编程



#include <iostream>
using namespace std;

int test_01() {
	int num = 702; //zz 26*26  肯定是三位数,702初始值减少时间
	for(char x = 'A'; x <= 'Z'; x++) {
		for(char y = 'A'; y <= 'Z'; y++) {
			for(char z = 'A'; z <= 'Z'; z++) {
				num++;
				if(num == 2019) {
					cout << x << y << z << endl;
					break; //停止循环减少时间
				}
			}
		}
	}
	return 0;
}



3.数列求值

f(n) = f(n - 3) + f(n - 3) + f(n - 2) + f(n - 1)
第20190325项的最后4位 :4659

int test_02() {
	int a = 1,b = 1,c = 1;
	int d = 0,n = 4;
	while(n != 20190325) {
		d = (a + b + c)%10000;   //除10^n^看做移小数点n位,取最后一位(个位) %10
		n++;
		a = b;
		b = c;
		c = d;
	}
	cout << d;
	return 0;
}
//法二 开数组
typedef long long ll;
const int maxn = 20190325;
ll a_03[20190330];
int test_03() {
	a_03[1] = a_03[2] = a_03[3] = 1;
	for(int i = 4; i < 20190325; i++) {
		a_03[i] = a_03[i - 1] + a_03[i - 2] + a_03[i - 3];
		a_03[i] %= 10000;
	}
	cout << a_03[20190324] << endl;
	return 0;
}






4.数的分解

2019分解成3个各不相同的数,且要求每个正整数都不包含数字2和4 (正整数没有0)
有多少种 :40785

bool check_04(int x) {
	int t = x;
	while(t) { //t==0时停止
		if(t % 10 == 2 || t % 10 == 4)return false;
		t /= 10;
	}
	return true;
}
int test_04() {
	int ans = 0;
	for(int x = 1; x < 2019; x++) { //正整数
		for(int y = x + 1; y < 2019; y++) { //各不相等
			int z = 2019 - x - y; //和为0
			if(check_04(x)&&check_04(y)&&check_04(z)&&(z > y)) { //内层最先遍历完   因为z减少循环确定2019,不需要再加条件(x + y + z) == 2019&&
				ans++;
			}
		}
	}
	cout << ans << endl;
	return 0;
}




补:蛇形矩阵找规律 对角线 1 5 13 25 41 即 ans += 4*i
可以先n= 5时 , 看ans是不是41验证算法的正确性

2013

1.猜年龄 (年轻就出席会议)

年龄3 为4位数 与年龄4 为6位数 ,这两个结果各个位刚好包含了0 - 9 十个数字,求年龄
(枚举范围自己先判断减小!)


int test_05() {
	for(int i = 10; i < 30; i++) {
		int i1 = i * i* i;
		int i2 = i*i*i*i;
		if(i1>=1000 && i1 <10000 && i2>= 100000 && i2 < 1000000) {
			cout<<i << " " << i1 <<" "<< i2 << endl; //肉眼观察是不是 0-9都有
		}
	}
	return 0; //发现符合18 5832 104976   --18岁

}

马虎的算式

ab * cde == abd * ce
设 abcde代表1 – 9 的5个不同数字
题目的提示:满足交换律,累加为不同种类,答案一定为偶数
答案:
142




#include<cstdio>
int test_06() {
	int ans = 0;
	for(int a = 1; a <= 9; a++) {
		for(int b = 1; b <= 9; b++) {
			if(a== b)continue;
			for(int c = 1; c <= 9; c++) {
				if(c == b || c== a )continue;  //之前已经保证 a != b ,这里等效成 if(c != b && c != a)for(){}
				for(int d = 1; d <= 9; d++) {
					if(d == c || d== b || d== a )continue;
					for(int e = 1; e <= 9; e++) {
						if(e == d || e == c || e == b || e == a )continue;
						if(  (a*10 + b)*(c*100+d*10+e) == (a*100+d*10+b)*(c*10 + e) ) { //这里printf验算
							ans++;
						}
					}
				}
			}
		}

	}
	cout << ans << endl;
	return 0;
}



振兴中华

每道题先看看有没有规律!

从我做起振
我做起振兴
做起振兴中
起振兴中华

只能上下左右跳相邻格子
遍历出:
从我做起振兴中华
问有几种跳跃路线
枚举:
1.迭代
2.递归


/*.......my思考
string maze[4];
string s1 ="从我做起振兴中华";
int d[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};
bool in(int x,int y){
	if(x >= 0 && x < 5 && y >= 0 && y < 5){
		return true;
	}
	return false;
}
void dfs(int x,int y){ //(0,0)

	for(int i = 0;i < 4;i++){
		int tx = x + d[i][0];
		int ty = y + d[i][1];
		if(in(tx,ty) && )
	}

}

int test_07(){
	for(int i = 0;i < 4;i++){
		cin >> maze[i] << endl;
	}


}
*/

//递归 先看有没有规律!!!
int f(int x,int y) {
	if(x == 3 || y == 4)return 1;
	return f(x + 1,y) + f(x , y + 1); //能发现规律地图是有规律的!!! 可以dp
}
int dp[5][5];
int test_07() {

	cout << f(0,0) << endl;
	return 0;
}



幻方填空 – 简单+耐心 (全排列)2n-1

1 – 16 填在 4 * 4 方格中
使得行、列、两条对角线上的数字之和都相等 ∑d[i][0] = ∑d[0][j] = ∑d[i][i] 写个check检查!
给出矩阵:
16 ? ? 13
? ? 11 ?
9 ? ? *
? 15 ? 1

计算出 ? 和 * 并提交 *
答案是1个整数
暴力法:10个数全排列 放入试试 填空题不考虑时间
c++自带的全排列函数: next_permutation() !!!!!
next_permutation()用法:
next_permutation按照字典序升序趋势,从当前状态向后做全排列。 数组顺序后移
也即,如果导入2,1,3.函数只会从213开始向后找其他排列。
如231,312,321。因此若要求某个序列的全排列,应当先升序排列,再导入

#include<vector>
#include<algorithm>
// 1 9 11 13 15 16
int a[] = {2,3,4,5,6,7,8,10,12,14}; //剩余未选择的元素
/*
16 ? ? 13
? ? 11 ?
9 ? ? *
? 15 ? 1

*/
void check(vector<int> arr) {
	int r1 = 29 + arr[0] + arr[1];
	int r2 = 11 + arr[2] + arr[3] + arr[4];
	int r3 = 9 + arr[5] + arr[6] + arr[7];
	int r4 = 16 + arr[8] + arr[9];

	int c1 = 25 + arr[2] + arr[8];  //按行填空的顺序
	int c2 = 15 + arr[0] + arr[3] + arr[5];
	int c3 = 11 + arr[1] + arr[6] + arr[9];
	int c4 = 14 + arr[4] + arr[7];

	int r = 17 + arr[3] + arr[6];     //下标从0开始第4个为下标 3
	int l = 24 + arr[5] + arr[8];

	if(r1 == r2 && r2 == r3 && r3 == r4&& c1 == c2&& c2 == c3&& c3 == c4&& r == l) {
		cout << arr[7] << endl;
		/*有时间可验证*/
		for(int i = 0; i < 10; i++) {
			cout <<arr[i] << " ";
		}
	}


}
int test_08() {
	vector<int> arr;
	for(int i = 0; i < 10; i++) {
		arr.push_back(a[i]);
	}
	do {
		check(arr);
	} while(next_permutation(arr.begin(),arr.end()));  //全排列遍历所有情况
	return 0;
}



公约数公倍数 (代码填空题)

填代码 坑点: a,b值已经变化,中间用m,n拷贝了 所有
应该填 m / 最大公约数 * n ( 防止爆炸,最大公约数代码中为b )

三步排序 (代码填空题)

负数靠左边,正数靠右边,0中间,负的与正的各自区域不要求有序
(快速排序变种题 – 小的移到左边,大的移到右边)
代码填空题(复制,看懂代码,填写代码,跑):
等于0的不动left指向第一个大等于0的, 填 mod++,//指向下一个区域

核桃的数量

读题目,对数字敏感
带领3个开发组
1.各组的核桃数量必须相同
2.组内必须能平分核桃
3.尽量满足1 ,2条件的最小数量

输入每组人数
2 4 5
输出一个正整数,表示每袋的核桃数量
20




int test_09() {
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	for(int i = 1; i <= a * b * c; i++) { //到a * b * c时,必能整除a ,b , c
		if(i % a == 0 && i % b == 0 && i % c == 0 ) {
			printf("%d\n",i);
			break;
		}
	}
	return 0;
}

打印十字图 (相对代码量巨大)

代码多
分析:
①1,2,3,4子问题不同 , 一段一段写
②1,2,3,4子问题类似 , 递归,迭代
每一圈模拟找规律
中间十字
数组空间 9 + (4 * (n - 1))2
从最外圈到1 (最内层十字)
每圈的每行找规律
一行:等差数列 5 - 9 -13 5 + (n - 1) * 4
二行: v1 - 2
三行
第四个部分(列连续的)
第五个部分 (与二行相同)
第六个部分(与一行相同)

#include<iostream>
using namespace std;
char arr_10[9 + 4 * 28][9 + 4 * 28];
void printAll_10(int l,int r) {
	for(int i = l; i <= r; i++) {
		for(int j = l; j <= r; j++) {
			if(arr_10[i][j] != '$') {
				arr_10[i][j] =  '.';
			}
			cout << arr_10[i][j] << " ";
		}
		cout << endl;
	}

}
/*现在输出最外层:    (此题特点,代码量大,若不是时间充裕,建议留到最后)
. . $ $ $ $ $ . .
. . $ . . . $ . .
$ $ $ . . . $ $ $
$ . . . . . . . $
$ . . . . . . . $
$ . . . . . . . $
$ $ $ . . . $ $ $
. . $ . . . $ . .
. . $ $ $ $ $ . .

*/
//只打印一圈 , 非完整题解!
int test_10() {
	int l = 0,r;  //每层就是l,r不一样 (2013 8-2...)
	int n;
	scanf("%d",&n);
	r = 9 + 4 * (n - 1) - 1; //可以取到的最大 下标

	//处理第一行,最后一行
	for(int i = 2; i <= r - 2; i++) {
		arr_10[l][i] = '$';
		arr_10[r][i] = '$';
	}
	//处理第二行,倒数第二行
	arr_10[1][2] = '$' ;
	arr_10[1][r - 2] = '$';
	arr_10[r-1][2] = '$';
	arr_10[r-1][r - 2] = '$';
	//处理第三行和倒数第三行
	arr_10[2][0] = '$';
	arr_10[2][1] = '$';
	arr_10[2][2] = '$';
	arr_10[2][r] = '$';
	arr_10[2][r-1] = '$';
	arr_10[2][r-2] = '$';
	arr_10[r-2][0] = '$';
	arr_10[r-2][1] = '$';
	arr_10[r-2][2] = '$';
	arr_10[r-2][r] = '$';
	arr_10[r-2][r-1] = '$';
	arr_10[r-2][r-2] = '$';

	//处理两边 (第4列到倒数第4列)
	for(int j = 3; j <= r-3; j++) {
		arr_10[j][0] = '$';
		arr_10[j][r] = '$';
	}
	printAll_10(l,r);

	return 0;
}



带分数

100 = 3 + 69258 / 714
还可以表示 100 = 82 + 3546 / 197
带分数特点: 数字1-9,分别出现且只出现一次(不包含0)
100 有 11种表示法
输入 N <1e6
输出 表示的方法数量


①枚举 1-98 + ()/() 限制:不重复数字
②全排列思考 ,插入+ 和 /
生成1~9的全排列,先在可能位置插入+ ,再在可能位置插入/ ,验算等式,计数
next_permutation()
头文件algorithm
do{//全排列模板

}
while(next_permutation(s.begin(),s.end()));


#include<iostream>
#include<string>
#include<cstdlib>   //c_str() 
#include<algorithm>
using namespace std;
//此处超时   但 可以 打表    ,还可以parse函数改造

int test_11() { // !!!!! 截取字符串会拷贝(也有一层循环!),反复开辟空间 的时间耗时 !!!!! 比较的常数时间很少
	int n,ans = 0;   // substr能不用就不用!!!!!! 
	scanf("%d",&n);
	string s = "123456789"; //+最多到7 ,后面要给 / 留位置
	do { //全排列模板
		for(int i = 1; i <= 7; i++) { //+号前面的串长度
			string a = s.substr(0,i); // 加号前面的数
			int inta = atoi(a.c_str());  //atoi字符串转整数int , 需要先转c_str

			if(inta >= n)break; //可行性剪枝 先想想哪些不可能的就先排除不用往下算了(不能大于n)

			for(int j = 1; j <= 9 - i - 1; j++) { // 两个符号之间的串的长度  (除号后面必须有数)
				string b = s.substr(i,j); // 除号前面的串   从i开始到j
				string c = s.substr(i + j); //除号后面的串   从某个位置开始截取到结束
				int intb = atoi(b.c_str());
				int intc = atoi(c.c_str());
				if(intb % intc == 0 && inta + intb / intc == n) {
					ans++;
				}
			}
		}
	} while(next_permutation(s.begin(),s.end()));
	printf("%d\n",ans);
	return 0;
}

剪格子

m*n 的格子是否可以切割成 两个部分,使得各个部分的数字和相等
如果存在多解,输出左上角格子的那个区域包含格子最小的数目
如果无分割,输出0
输入 (m列 n行 数值)
3 3
10 1 52
20 30 1
1 2 3
输出: (满足条件左上区域最小格子数)
3
输入2:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
输出2:
10

思路: 遍历(走迷宫)累加走过的数值 == 总值/2 就等效满足
本质:图的连通 --> DFS (算法基础题:水洼)
过程中 > c/2 break; 递归+回溯+剪枝

#include<algorithm>  //min
int m,n,total;
int g[10][10];
int ans = 100; //最多 n*m 上限100
int d[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
bool vis[10][10];
bool in(int x,int y) {
	if(0 <= x && x < n && y >= 0 && y < m) {
		return true;
	}
	return false;
}
void dfs(int i,int j,int sum,int  cnt) {  

	if(sum > total/2)return;
	if(sum == total/2) {
		ans = min(ans , cnt);
	}
	vis[i][j] = true;
	//四个方向 (与迷宫走法有区别,也是考虑路径最优 ,可能蛇形走位...)

	if(i + 1 < n && !vis[i + 1][j])dfs(i + 1,j,sum + g[i][j], cnt + 1);  //可以往下走的条件
	if(i - 1 >= 0 && !vis[i - 1][j])dfs(i - 1,j,sum + g[i][j], cnt + 1); //可以往上走
	if(j + 1 < m && !vis[i][j + 1])dfs(i,j + 1,sum + g[i][j], cnt + 1); //可以往右走
	if(j - 1 >= 0 && !vis[i][j - 1])dfs(i,j - 1,sum + g[i][j], cnt + 1); //可以往左走
/*	
	for(int k; k < 4; k++) {   //bug!!
		int	tx = i + d[k][0];
		int	ty = j + d[k][1];
		if(in(tx,ty)&&!vis[tx][ty]) {
			dfs(tx,ty,sum + g[i][j],cnt + 1);
		}
	}
*/
	vis[i][j] = false;//回溯



}
//不足:若
/*
2 2
1 1
1 3
0  因为 1 1 dfs不会回溯到另一个1,认为无解,输出0 
*/

int test_12() {
	scanf("%d%d",&m,&n);  //题坑 ,先输入列 再输入行
	for(int i = 0; i < n; i++) {
		for(int j = 0; j < m; j++) {
			scanf("%d",&g[i][j]);
			total += g[i][j];
		}
	}
	dfs(0,0,0,0);
	if(ans != 100){
	printf("%d\n",ans);
	}
	else{
		printf("%d\n",0);
	}
	return 0;
}

2013年真题小结

01 猜年龄 枚举
02 马虎的算式 枚举加验证 ab*cde = aeb * df
03 振兴中华 递归
04 幻方填空 全排列(集合有序)
05 公约数公倍数
06 三步排序 快速排序 (三指针)的变体
07 核桃的数量 简单枚举
08 打印十字图 先写死再写活 (有规律)
09 带分数 全排列 + 枚举加号和除号的插入位置 -> 检查(剪枝) ,手工写字符串转整数
10 剪格子 深搜 + 回溯 + 剪枝 (要点:能想到sum == total/2 为结束条件)

int main() {

	test_12();

	return 0;
}

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

violet~evergarden

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值