计算机保研机试准备——C++算法题
前言:
本人不是ACMer!!!(大佬可以跳过了😅)去年用Python打过🏀杯,后来发现大多数高校都是C++,有些不支持Python语言,而且过去一年一直泡在实验室肝科研没咋练过题,所以改用C++把之前总结的模板和算法再拾一拾。写博客一方面敦促自己每天刷题,另一方面给和我一样算法蒟蒻cs保研er提供参考,加油吧陌生人!
所用网站: 洛谷 + Leetcode(力扣) 以洛谷为主是为了保证全流程规范刷题(尤其输入输出,力扣没有这些),力扣为辅是为了多见见题型。
ps:文章只提供题目链接和我写的题解,偶尔典型题会加一下自己的见解(这些题网上教程讲解已经很详细了:“前人之述备矣”,而且都2025年了不会还有人不会用大模型辅助刷题吧)
另外下面这个专栏里有我去年打比赛整理的经典算法模板(全网综合提炼加上自己的优化修改,精华中的精华),虽然是用python写的但算法模板放在哪个语言上都大差不差,可以去看一下(别忘了点赞收藏哦♥)后续模板会接着更新
算法专栏https://blog.csdn.net/weixin_47520540/category_12599067.html?fromshare=blogcolumn&sharetype=blogcolumn&sharerId=12599067&sharerefer=PC&sharesource=weixin_47520540&sharefrom=from_link
一、入门基础题
这里主要是一些练手题俗称签到题,熟悉C++基本语法
(1)P1001 A+B Problem
#include <iostream>
using namespace std;
int main(){int a,b;cin >> a >>b;cout << a+b;return 0 ;
}
(2)P5015 [NOIP 2018 普及组] 标题统计
#include <iostream>
#include <string>
using namespace std;
int main(){string s;getline(cin,s); //注意getline函数的使用int res = 0;for(int i = 0;i<s.size();i++){if (s[i] != ' ' &&s[i] != '\n'){res ++;}}cout << res;return 0;}
(3)P1035 [NOIP 2002 普及组] 级数求和
这道题一个注意遇到分数要定义double类型,还有最后输出边界的考量(n还是n-1)
#include<iostream>
using namespace std;
int main(){int k,n;double s,ans; cin >> k;s =0;n = 1;while(s<=k){s += 1.0/n;n += 1; }cout << n-1 << endl;return 0;
}
(4)P1008 [NOIP 1998 普及组] 三连击
这道题稍微上点难度,有两种解法从不同的角度出发,都写了详细注释
// 第一种解法:
#include <iostream>
#include <string>
using namespace std;
bool st[10]; //标记数组,st[i] 表示数字 i(1–9)是否已经被使用过。
string str; //用来动态拼接当前已选的数字字符,总长度最多 9(对应 9 个数字)。
void dfs(int x){ //参数 x 表示当前已经放了多少个数字字符(初始为 0)。// 当已经选满 9 个数字时,尝试检验比例//stoi: 将数字字符转化位int输出if(x == 9){int a = stoi(str.substr(0,3)) ;//substr:获得str中从第0位到长度为3的字符串int b = stoi(str.substr(3,3));int c = stoi(str.substr(6,3));if(a*2 == b && a*3 == c){cout <<a<<" "<<b<<" "<<c<<endl;}return;// 回到上一层,继续枚举其它排列}// 枚举下一个位置要放的数字for(int i = 1;i<10;i++){if(!st[i]){ // 如果数字 i 还没被用过st[i]=true; // 标记为已用str.push_back(i+'0'); // 把 i 转成字符,追加到 str 末尾dfs(x+1);// 递归处理下一个位置st[i] = false; // 回溯:撤销使用标记str.pop_back(); // 回溯:删除刚才追加的字符}}// 深度优先枚举的思路,就是把 1…9 全部排列(共 9! 种),在排列的基础上取前三位、次三位、末三位分别当作 a,b,c,再筛选比例。
}
int main(){dfs(0);return 0;
}
----------------------
//另一种方法:
#include <iostream>
using namespace std;// 检查 n 的三个十进制数字,
// 在标记数组 vis 上打标记;
// 如果发现 0 或重复数字,返回 false。
bool mark3(int n, bool vis[]) {for (int i = 0; i < 3; i++) {int d = n % 10;if (d == 0 || vis[d]) return false;vis[d] = true;n /= 10;}return true;
}
int main() {// 枚举 a,从 123 开始到 329(因为 3*330 = 990 > 999)for (int a = 123; a <= 329; a++) {int b = 2 * a;int c = 3 * a;if (b >= 1000 || c >= 1000) continue;bool vis[10] = {}; // vis[1..9] 用来标记数字是否出现过// 先标记 a 的三位if (!mark3(a, vis)) continue;// 再标记 b 的三位if (!mark3(b, vis)) continue;// 再标记 c 的三位if (!mark3(c, vis)) continue;// 最后检查 1..9 都被标记过bool ok = true;for (int d = 1; d <= 9; d++) {if (!vis[d]) { ok = false; break; }}if (ok) {cout << a << " " << b << " " << c << "\n";}}return 0;
}
(5)P1909 [NOIP 2016 普及组] 买铅笔
这里有两种方法,这里补充一下ceil这一类cmath标准库: C++取整
//笨方法
#include<iostream>
using namespace std;
int main(){int n,a1,a2,b1,b2,c1,c2,res1,res2,res3,ans;// n 为铅笔数量 a,b,c为三种包装(下标1为数量,2为价格) res为每种包装的总价,ans为最终价格cin >>n>>a1>>a2>>b1>>b2>>c1>>c2;if(n % a1 != 0) res1 = (n/a1 +1)*a2 ;//重点理解这里取整和取余else res1= (n/a1)*a2;if(n % b1 != 0) res2 = (n/b1 +1)*b2 ;else res2= (n/b1)*b2;if(n % c1 != 0) res3 = (n/c1 +1)*c2 ;else res3= (n/c1)*c2;//比较if(res1<res2)ans = res1;else ans = res2; //注意这里比较后赋值可减少比较次数if(res3<ans) ans = res3;cout <<ans ;return 0;
}
//使用内置函数快捷
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int main(){int n,a1,a2,b1,b2,c1,c2,res1,res2,res3,ans;// n 为铅笔数量 a,b,c为三种包装(下标1为数量,2为价格) res为每种包装的总价,ans为最终价格cin >>n>>a1>>a2>>b1>>b2>>c1>>c2;res1 = ceil(1.0*n/a1)*a2; //乘1.0是为了确保 ceil内为浮点数而非整数res2 = ceil(1.0*n/b1)*b2;res3 = ceil(1.0*n/c1)*c2;ans = min({res1,res2,res3});cout <<ans ;return 0;
}
4.15记录-----未完待续......