蓝桥杯校内选拔
校内选拔两道题 --- 两小时
第一题:
编程题一:数字三角形
问题描述
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路
径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求
出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。
输入数据
输入的第一行是一个整数 N (1 < N <= 100),给出三角形的行数。下面的N 行给出数字
三角形。数字三角形上的数的范围都在0 和100 之间。
输出要求
输出最大的和。
输入样例
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出样例
30
刚好前几天看到了动态规划,就是一个简单的动态规划问题。
关键是写出状态转移方程
for(int i=N; i>=1; i--){ for(int j=1; j<=i; j++){ dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + a[i][j]; //dp[][]二维数组保存当前点到最下层的路径最大值,a[][]二维数组保存的是当前点的值 } }
第二题:
编程题二:称硬币
问题描述
赛利有 12 枚银币。其中有11 枚真币和1 枚假币。假币看起来和真币没有区别,但是重
量不同。但赛利不知道假币比真币轻还是重。于是他向朋友借了一架天平。朋友希望赛利称
三次就能找出假币并且确定假币是轻是重。例如:如果赛利用天平称两枚硬币,发现天平平
衡,说明两枚都是真的。如果赛利用一枚真币与另一枚银币比较,发现它比真币轻或重,说
明它是假币。经过精心安排每次的称量,赛利保证在称三次后确定假币。
输入数据
输入有三行,每行表示一次称量的结果。赛利事先将银币标号为A-L。每次称量的结果
用三个以空格隔开的字符串表示:天平左边放置的硬币 天平右边放置的硬币 平衡状态。其
中平衡状态用"up'', "down'', 或 "even''表示, 分别为右端高、右端低和平衡。天平左右的硬币
数总是相等的。
输出要求:
输出哪一个标号的银币是假币,并说明它比真币轻还是重。
输入样例
1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even
输出样例
K is the counterfeit coin and it is light.
挂在了第二题(当时好像纠结了很久怎么把ABCD和EFGH之间的空格输入才不会影响后面的字符串的输入),想想自己还真是太水了...这样的题目好像是水题,不需要什么高级算法知识...
后面看了很多大佬的代码,想通了。。。就是先将三行字符串输入,然后再枚举...
#include<iostream> #include<string.h> using namespace std; //当时死在这题一直在想ABCD和EFGH中间的空格要怎么跳过才不会影响后面的输入 char Left[3][5]; //注意这里在设置left和right数组的时候数组名字第一个字母大写,不然会和库函数名字相同。导致后面又要修改程序,浪费时间 char Right[3][5]; char flag[3][5]; bool f[12]; //存储 A-L 对应的数字下标的真假, true表示肯定为真 bool is_light(char ch){ for(int i=0; i<3; i++){ switch(flag[i][0]){ case 'e' : if(strchr(Left[i], ch) || strchr(Right[i], ch)) return false;break; case 'u' : if(strchr(Left[i], ch)) return false;break; case 'd' : if(strchr(Right[i], ch)) return false;break; } } return true; } bool is_heavy(char ch){ for(int i=0; i<3; i++){ switch(flag[i][0]){ case 'e' : if(strchr(Left[i], ch) || strchr(Right[i], ch)) return false;break; case 'u' : if(strchr(Right[i], ch)) return false;break; case 'd' : if(strchr(Left[i], ch)) return false;break; } } return true; } int main(){ int T; cin >> T; while(T--){ for(int i=0; i<3; i++){ cin >> Left[i] >> Right[i] >> flag[i]; if(flag[i] == "even"){ int len = strlen(Left[i]); for(int j=0; j<len; j++){ f[Left[i][j] - 'A'] = f[Right[i][j] - 'A'] = true; } } } for(char ch='A'; ch <= 'L'; ch++){ if(f[ch - 'A']) continue; if(is_light(ch)) { cout << ch << " is the counterfeit coin and it is light." << endl; break; } if(is_heavy(ch)){ cout << ch << " is the counterfeit coin and it is heavy." << endl; break; } } } return 0; }
这个称硬币的思想是这样的:
四个四个比较(假设先比较ABCD 和 EFGH)
有两种情况:
1.even(等重)
那么假币一定在IJKL中
然后把IJKL中的四个硬币拿三个出来分别代替之前的两边的几个真的硬币 如:ABCI 和 EFJK
然后又有两种情况
1)等重 那么假币一定是L(接下来判断它 的轻重就可以了)
2)不等重 假设左边重(说明要么是I重要么是JK中有一个轻了),接下来把J和C换一下位置,如果左重(I为假币且比真币重),如果左轻(J为假币且比真币轻),如果右轻(K为假币且比真币轻)
2.思想是一样的
这是人的计算逻辑,用计算机的话就是枚举,方法是:先将字符串保存,然后从A-L枚举,如果字符存在等重的那一行,那么硬币一定为真(即该字符标志设置为true或者返回FALSE),如果该行中 判断为down(即右边重),那么在is_light(轻)的判断中只要它出现在右边就返回FALSE,在is_heavy(重)的判断中只要它出现在左边就返回FALSE,判断为 up同理...