计算机保研机试准备——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记录-----未完待续......

(6)P1307 [NOIP 2011 普及组] 数字反转  

取整/取余是常见的操作数字位数的手段

//因为反转后0要舍去,故不宜转为字符串
#include<bits/stdc++.h>
using namespace std;
int main(){
  int n = 0,s = 0;
  for(cin>>n; n!=0; n/=10) s = s*10+n%10;
  cout << s;
  return 0 ;
}

(7)P1014 [NOIP 1999 普及组] Cantor 表

很考验思维的一道题,建议多思考思考,对锻炼模拟和枚举思维很有帮助

//模拟枚举
#include<bits/stdc++.h>
using namespace std;
int main(){
  //z编号后每一行比上一行多一
  int n , k = 1;
  cin >> n;
  //每次k+1,判断最终的位置,k的奇偶判断正(如2)反(如3)
  //出循环后此时k表示第k条对角线,n表示在该对角线上的位置。
  while(n>k){
    n = n-k;
    k++;
  }
  //k偶数行分子随第几(n)顺序递增,也就是分子为n,分母从k行开始递减(k,k-1,k-2,k-3...)第n个项的分母为k-(n-1)=k+1-n(观察规律可得)  k为奇则反过来
  if (k%2 ==0){
    cout << n << "/"<< (k+1-n);
  }
  else cout << (k+1-n) << "/" << n;
  return 0;

}

----------4.19未完待续......

二、数组基础题

(8)P1046 [NOIP 2005 普及组] 陶陶摘苹果

基础数组题

#include<bits/stdc++.h>
using namespace std;
int main(){
  int num[10],n,res=0;
  for(int i = 0;i<10;i++) cin >> num[i];
  cin >> n;
  for(int i =0;i<10;i++){
    if(n+30 >= num[i]) res++;
  } 
  cout << res;
  return 0;
}

(9)P1427 小鱼的数字游戏

数组操作题,easy

#include<bits/stdc++.h>
using namespace std;
int m[101],c=0;
int main(){
  for(int i=0;;i++){
    cin>>m[i];
    if(m[i]==0) break;
    c = i;
  }
  for(int j=c;j>=0;j--)
  cout << m[j] <<' ';
  return 0 ;

}

(10)P1047 [NOIP 2005 普及组] 校门外的树

标记数组

// 碰到重合问题 会用flag = true标记
#include<bits/stdc++.h>
using namespace std;
int res = 0;
bool num[10001]; //标记数组
int main(){
  int n,m,l,r;
  cin >> n>>m;
  for (int i =0;i<m;i++){
    cin >> l>>r;
    for(int j = l;j<=r;j++){
      num[j] = true ;//树已被记录
    }
  }
  for (int i = 0;i<=n;i++){
    if (!num[i]){
      res++;
    }
  }
  cout << res;
  return 0;
}

三、字符串基础题

(11)P1055 [NOIP 2008 普及组] ISBN 号码

#include<bits/stdc++.h>
using namespace std;
int main(){
  int a,b,c;
  char m,n;
  scanf("%d-%d-%d-%c",&a,&b,&c,&m);
  int tmp = (a+ (b / 100) * 2 + (b % 100 / 10) * 3 + (b % 10) * 4 + (c / 10000) * 5 + (c % 10000 / 1000) * 6 + (c % 1000 / 100) * 7 + (c % 100 / 10) * 8 + (c % 10) * 9)%11 ;
  if(tmp==10) n = 'X';
  else n = tmp+'0';  //+'0'转化为char
  if (m==n) cout << "Right";//字符串必须使用双引号
  else cout << a<<'-'<<b<<'-'<<c<<'-'<<n;
  return 0;
}

(12)P5015 [NOIP 2018 普及组] 标题统计

签到题

#include<bits/stdc++.h>
using namespace std;
int main(){
  int res = 0;
  string s;
  getline(cin,s);
  for(int i=0;i<s.size();i++){
    if(s[i]!=' '&& s[i]!= '\n') res ++;
  }
  cout << res;
  return 0;
}

(13)P1308 [NOIP 2011 普及组] 统计单词数

#include<bits/stdc++.h>
using namespace std;
int main(){
  string w,s;
  // 输入目标单词并转换为小写
  cin >> w ;
  for(int i=0;i<w.size();i++) w[i] = tolower(w[i]);
  //文章处理
  getchar(); // 清除输入缓冲区中的换行符 
  getline(cin,s);
  int id= -1; // 记录第一次出现的位置,初始值为-1表示未找到
  int cut = 0;// 统计出现次数
  
   //遍历
  for(int i=0;i<s.size();i++){
    if(s[i]== ' ')continue; //空格跳出本次循环
    int st = i; //st为当前单词起始的位置
    int e = 0;  //用于确定单词的结束位置
    e = i;
    //将当前单词变小写,找到单词结束的位置
    while(e<s.size()&&s[e]!=' '){
      s[e]=tolower(s[e]) ;e++;
    }
    //进行比较
    if(w == s.substr(st,e-st)) //substr:获得str中从第0位到长度
    {
      if(id == -1){
        id =st;  // 记录第一次出现的位置
      }
      cut++;
    }
    i= e-1;//更新主循环的索引
    
  }
  //输出
  if(id==-1){  //由id可发现没找到
        cout << id <<endl;
    }else{
      cout << cut<<' '<< id<<endl;
    }
  return 0;
}

(14)P2010 [NOIP 2016 普及组] 回文日期

#include<bits/stdc++.h>
using namespace std;
bool cmp(string a,string b){
  return a+b > b+a;
}
int main(){
  int n;
  cin >> n;
  string m[21];
  for (int i = 0; i < n; i++) {
		cin >> m[i];
	}
  //nums 数组从第一个元素到第 n 个元素(不包括 nums + n)按照自定义的比较函数 cmp 进行排序
  sort(m,m+n,cmp);
  for(int i=0;i<n;i++){
    cout << m[i];
  }
  return 0;
}

--------4.28 记

以上是所有比较典型的基础入门题(不涉及复杂算法如递归、二分、模拟等)

下一篇将涉及递归和递推、简单dp、排序、模拟、分治这些简单算法,尽情期待~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值