备战蓝桥杯(3)

一、蛇形矩阵

cpp 复制代码
#include<iostream>        
using namespace std;      

int main(){              
    int N;                 // 定义一个整数变量N,用于存储用户输入的数字
    cin>>N;                // 从键盘输入N的值(决定输出多少行和列)
    
    int v[105][105];       // 定义一个105行105列的二维整数数组v(预留足够空间)
    
    v[0][0]=1;             // 设置数组第一个元素(左上角)的值为1
    
    // 第一个循环:填充第一列的数据
    for(int i=1 ; i<100 ;i++){       
        v[i][0] = v[i-1][0]+i;        // 当前行的第一列 = 上一行的第一列 + 当前行号
    // 这样第一列形成数列:1, 2, 4, 7, 11, 16, ...
                                    
    }
    
    int zero_one=2;        // 定义一个变量zero_one,初始值为2(用于控制每行起始的间隔)
    
    // 第二个循环:填充整个二维数组的所有列
    for(int i=0 ; i<100 ;i++){        // 遍历每一行(0到99行)
        int interval=zero_one;         // 设置当前行的起始间隔为zero_one的值
        for(int j=1 ; j<100 ;j++){     // 遍历每一列(从第1列开始到第99列)
            v[i][j] = v[i][j-1]+interval;  // 当前元素 = 左边相邻元素 + 当前间隔
            interval++;                     // 间隔递增1(每向右一列,间隔+1)
        }
        zero_one++;                 // 每完成一行,zero_one加1(下一行的起始间隔更大)
    }
    
    int lie=N;           // 定义一个变量lie,初始值为N(控制每行输出的列数)
    
    // 第三个循环:按照特定格式输出数组内容
    for(int i=0 ; i<N ;i++){        // 输出前N行(i从0到N-1)
        for(int j=0 ;j<lie;j++){    // 输出当前行的前lie列(lie逐渐减少)
            cout<<v[i][j]<<" ";      // 输出数组元素,后面跟一个空格
        }
        lie--;                       // 每行输出完后,lie减1(下一行少输出一列)
        cout<<endl;                  // 每行结束后换行
    }
    
    return 0;          
}

二、淘淘摘苹果

cpp 复制代码
#include<iostream>        
using namespace std;      

int main(){                
    int a[10];             // 定义一个长度为10的整型数组a,用于存储10个整数
    
    // 第一个循环:读取10个整数存入数组
    for(int i=0 ; i<10 ;i++){        // 循环10次,i从0到9
        cin>>a[i];                    // 从键盘输入一个整数,存入数组的第i个位置
    }
    
    int arm;                // 定义一个整数变量arm(表示手臂长度)
    cin>>arm;               // 从键盘输入arm的值
    
    int getlong=arm+30;     // 定义一个变量getlong,值为arm + 30
                            // 是手臂长度加上30厘米(拿东西的最大高度)
    
    int sum=0;              // 定义一个计数器sum,初始值为0
    
    // 第二个循环:统计数组中有多少个元素不超过getlong
    for(int i=0 ; i<10 ;i++){        // 遍历数组的10个元素
        if(a[i]<=getlong){           // 如果当前元素的值小于等于getlong
            sum++;                   // 计数器加1
        }
    }
    
    cout<<sum;              // 输出统计结果(有多少个数字不超过arm+30)
    
    return 0;               
}

三、明明的随机数

cpp 复制代码
#include<iostream>      
#include<algorithm>       // 包含算法库,用于sort排序函数
using namespace std;     

int main(){              
    int N;                 // 定义一个整数变量N,表示要输入的数字个数
    cin>>N;                // 从键盘输入N的值
    
    int a[N];              // 定义一个长度为N的数组a(变长数组,用于存储原始数据)
    
    // 第一个循环:读取N个整数存入数组a
    for(int i=0 ; i<N ;i++){      
        cin>>a[i];                    
    }
    
    sort(a, a+N);           // 使用sort函数对数组a进行排序
                            // a是数组首地址,a+N是尾地址,将a[0]到a[N-1]按升序排序
    
    int b[N];               // 定义一个长度为N的数组b,用于存储去重后的结果
    
    b[0]=a[0];              // 将排序后数组的第一个元素存入b的第一个位置
    int tag=1;              // 定义一个计数器tag,初始值为1,表示b数组中已有1个元素
    
    // 第二个循环:遍历排序后的数组a,进行去重操作
    for(int i=1 ; i<N ;i++){        // 从第1个元素开始遍历到最后一个(i从1到N-1)
        if(a[i]!=a[i-1]){            // 如果当前元素不等于前一个元素(发现新数字)
            b[tag]=a[i];              // 将当前元素存入b数组的第tag个位置
            tag++;                     // tag加1,表示又找到一个不重复的元素
        }
        // 如果a[i]等于a[i-1],说明是重复元素,跳过不处理
    }
    
    cout<<tag<<endl;        // 输出去重后的元素个数(即不重复数字的个数)
    
    // 第三个循环:输出b数组中存储的去重后的所有元素
    for(int i=0 ; i<tag ;i++){        // 循环tag次,输出所有不重复的数字
        cout<<b[i];                 )
    }
    
    return 0;               
}
复制代码
// 只对前5个元素排序
sort(arr, arr + 5);
复制代码
// 只对第3到第7个元素排序(索引2到6)
int arr2[] = {5, 2, 8, 1, 9, 3, 7, 4, 6};
sort(arr2 + 2, arr2 + 7);

C++标准库采用左闭右开区间 [start, end):

包含起始地址指向的元素

不包含结束地址指向的元素

四、奖学金

cpp 复制代码
#include<iostream>        // 包含输入输出流库,用于cin和cout
#include<cmath>           // 包含数学函数库,用于pow()幂运算
#include<algorithm>       // 包含算法库,用于sort排序
using namespace std;       // 使用标准命名空间

// 自定义比较函数,用于降序排序
bool cmp(int a , int b){
    return a > b;          // 返回a>b表示降序排列
}

int main(){
    int nn, numbers = 1;   // nn:学生人数, numbers:用于记录nn的位数
    cin >> nn;             // 输入学生人数
    int p = nn;            // 将nn赋值给p,用于计算位数
    
    // 计算nn的位数(例如:nn=100,则numbers=3)
    while(p / 10 != 0){     // 当p除以10不等于0(即p还有更多位)
        numbers++;           // 位数加1
        p = p / 10;          // p除以10,去掉最后一位
    }
    // 循环结束后,numbers就是nn的位数
    
    int a[nn];              // 定义数组a,用于存储编码后的学生信息
    
    // 输入每个学生的成绩并编码
    for(int i = 0; i < nn; i++){
        int x, y, z;         // x:语文, y:数学, z:英语
        cin >> x >> y >> z;
        int score = x + y + z;  // 计算总分
        
        // 核心编码公式!将多个信息编码成一个整数
        a[i] = (int)(score * pow(10, numbers + 2) +   // 高位:总分
                     x * pow(10, numbers) +           // 中位:语文成绩
                     nn - i);                          // 低位:学号信息
        // 解释:
        // pow(10, numbers+2) 创建了一个足够大的移位量
        // pow(10, numbers) 创建了中间位的移位量
        // nn-i 实现了学号越小,这个值越大(因为减i)
    }
    
    // 排序:按编码值从大到小排序
    sort(a, a + nn, cmp);   // 使用自定义的cmp函数进行降序排序
    
    // 输出前5名(如果人数少于5,则输出全部)
    for(int i = 0; i < min(5, nn); i++){
        // 解码并输出
        // 学号 = 1 + nn - (a[i] % 10)  
        // 因为编码时最后一位是 nn-i,所以 a[i] % 10 得到的就是 nn-i
        // 那么 i = nn - (a[i] % 10),学号 = i + 1
        cout << 1 + nn - (a[i] % 10) << " ";
        
        // 总分 = a[i] / 10^(numbers+2)  (取高位)
        cout << a[i] / (int)pow(10, numbers + 2) << endl;
    }
    
    return 0;
}

五、纪念品分组

cpp 复制代码
#include<iostream>        
#include<algorithm>       // 包含算法库,用于sort排序函数
using namespace std;       

int main(){           
    int w, n;              // w:每组纪念品的重量上限, n:纪念品件数
    cin >> w >> n;         // 从键盘输入w和n的值
    
    int a[n];              // 定义数组a,存储每件纪念品的重量
                           // 注意:这是变长数组(VLA),不是标准C++,但很多编译器支持
    
    // 循环输入n件纪念品的重量
    for(int i = 0; i < n; i++){    // i从0到n-1
        cin >> a[i];               // 输入第i件纪念品的重量
    }
    
    sort(a, a + n);         // 对纪念品重量进行升序排序
                            // 排序后:a[0]最小,a[n-1]最大
    
    int low = 0, high = n - 1;  // 双指针:low指向最轻的,high指向最重的
    int number = 0;              // 计数器,记录需要的组数
    
    // 当low指针不超过high指针时循环(即还有纪念品未分组)
    while(low <= high){
        // 情况1:只剩最后一件纪念品
        if(low == high){
            number++;        // 单独成一組
            break;           // 结束循环
        }
        
        // 情况2:最轻的和最重的可以放在一组
        if(a[low] + a[high] <= w){
            number++;        // 组数加1
            low++;           // 最轻的被分走,low指针右移
            high--;          // 最重的被分走,high指针左移
        }
        // 情况3:最轻的和最重的不能放在一组
        else{
            number++;        // 组数加1
            high--;          // 最重的单独成一组,high指针左移
                             // low指针不动,最轻的等待与下一个最重的配对
        }
    }
    
    cout << number;          // 输出最少需要的组数
    return 0;             
}

六、买不到的数目(真题)

cpp 复制代码
#include<iostream>       
using namespace std;      

int main(){                
    int x, y, result, minn, continuenumber;  
    // x和y:两种包装的糖果数量
    // result:最终结果(最大不能组合的数)
    // minn:x和y中较小的数
    // continuenumber:连续可以组合的数的个数计数器
    
    cin >> x >> y;          // 输入两种包装的糖果数量
    minn = min(x, y);       // 取x和y中较小的数,用于判断连续区间
    
    for(int i = 1; ; i++){
        int flag = 0;        // 标记当前数i是否可以由x和y组合而成,0表示不能
        
        // 尝试用j个x包装,看剩下的能否用y包装
        for(int j = 0; j * x <= i; j++){  // j从0开始,直到j*x超过i
            // 如果减去j个x后,剩下的数量能被y整除
            if((i - j * x) % y == 0){
                flag = 1;    // 标记为可以组合(找到了一个组合方式)
            }
        }
        

        if(flag != 1){
            result = i;          // 记录当前不能组合的数
            continuenumber = 0;   // 连续计数器重置为0
        }
        else{
            continuenumber++;     // 可以组合,连续计数器加1
        }
        
        // 核心判断条件:如果连续可以组合的数的个数达到了minn
        if(continuenumber == minn){
            break;                // 找到答案,退出循环
        }
    }
    
    cout << result;          // 输出最大不能组合的数
    return 0;               
}

七、数字游戏(真题)

cpp 复制代码
#include<iostream>               
using namespace std;              

int main(){                     
    int n, k, T;                  
    // n: 间隔数(每隔n个数取一次)
    // k: 取模的数(所有计算都对k取模)
    // T: 要取的总次数
    
    cin >> n >> k >> T;             // 从键盘输入n、k、T的值
    
    int a[T * n];                    // 定义数组a,大小为T*n
    // 足够存储所有需要计算的值,其实最精确且不浪费空间的为a[(T-1)×n+1]
    
    a[0] = 1;                        // 初始化第一个数字为1
    int result = 1;                  // 结果初始为1(已经取了第一个数)
    
    // 循环计算数组的每个元素
    // i从1开始,到T*n-1结束(因为数组索引从0到T*n-1)
    for(int i = 1; i < T * n; i++){        
        // 计算当前元素的值
        // 递推公式:当前值 = (前一个值 + 当前索引) % k
        a[i] = (a[i-1] + i) % k;
        
        // 判断是否是栋栋取的当前值
        if(i % n == 0){
            result += a[i];          // 把当前数加到结果中
        }
    }
    
    cout << result;                 
    return 0;                        
}
复制代码
n=2, k=10, T=4
需要索引:0,2,4,6
数组大小=8,索引0-7
循环i=1-7,取i=2,4,6 → 正确

n=4, k=20, T=3
需要索引:0,4,8
数组大小=12,索引0-11
循环i=1-11,取i=4,8 → 正确

八、核桃的数量(真题)

cpp 复制代码
#include<iostream>
using namespace std;
int main(){
	int a,b,c;
	cin>>a>>b>>c; 
	int maxx = max(max(a,b),c);
	while(1){
		if(maxx%a==0 && maxx%b==0 && maxx%c==0){
			break;
		}
		else{
			maxx++;
		}
	}
	cout<<maxx;
	return 0;
} 

其实本题就是求最小公倍数

九、连号区间数

因为N个数字都不同,所以区间的最大值-最小值 = 区间长度-1 = (R-L+1)-1 = R-L

sort 需要传入地址范围,而不是元素值

应该用 sort(a+i, a+j+1) 才能排序区间 i, j

cpp 复制代码
#include<iostream>       
#include<algorithm>       // 包含算法库,用于max和min函数
using namespace std;    

int main(){           
    int N;                 
    cin>>N;                // 从键盘输入N的值
    
    int a[N];          // 定义数组a,用于存储输入的1~N的排列
    
    // 第一个循环:输入数组元素
    for(int i=0; i<N; i++){     
        cin>>a[i];                  
    }
    
    int count = 0;          // 定义计数器count,初始值为0
   // 用于统计连号区间的个数
    
    // 外层循环:枚举所有可能的区间起点
    for(int i=0; i<N; i++){        // i从0到N-1,作为区间左端点
        int maxVal = a[i];           // 初始化当前区间最大值为a[i]
        int minVal = a[i];           // 初始化当前区间最小值为a[i]
        
        // 内层循环:从起点i开始,枚举所有可能的区间终点
        for(int j=i; j<N; j++){        // j从i到N-1,作为区间右端点
            // 动态更新当前区间[i, j]的最大值和最小值
            maxVal = max(maxVal, a[j]);  // 将a[j]与当前最大值比较,取较大者
            minVal = min(minVal, a[j]);  // 将a[j]与当前最小值比较,取较小者
            
            // 判断当前区间是否为连号区间
            // 关键性质:在1~N的排列中,区间是连号区间 ⇔ 最大值-最小值 = 区间长度-1
            // 区间长度 = j-i+1,所以区间长度-1 = j-i
            if(maxVal - minVal == j - i){  // 如果最大值与最小值的差等于区间长度-1
                count++;                     // 计数器加1,找到一个连号区间
            }
            // 如果不满足条件,说明当前区间不是连号区间,继续扩大区间
        }
    }
    
    cout << count << endl;  
    
    return 0;            
}

十、哈夫曼树

每次合并减少一个元素

循环次数 开始时元素个数 合并后元素个数 剩余未合并元素
初始状态 n n n个独立元素
第1次合并 n n-1 剩下n-1个"元素"(有些是合并结果)
第2次合并 n-1 n-2 剩下n-2个"元素"
... ... ... ...
第k次合并 n-k+1 n-k 剩下n-k个"元素"
第n-1次合并 2 1 剩下1个最终结果

直观理解

  • 一开始有 n 个数

  • 每次合并操作,会把两个数变成一个数 → 总数减少1

  • 要从 n 个数变成 1 个数,需要减少 n-1 次

  • 所以需要 n-1 次合并

cpp 复制代码
#include <iostream>      
#include<algorithm>        // 包含算法库,用于sort排序函数
using namespace std;       

int main(){              
    int n, add, sum = 0;  
    cin >> n;               // 从键盘输入学生人数n
    
    int a[n];               // 定义长度为n的数组a,用于存储每个学生的成绩或合并后的结果
    
    // 第一个循环:读取n个学生的初始成绩
    for(int i = 0; i < n; i++) {    // 循环n次,i从0到n-1
        cin >> a[i];                  // 输入第i个学生的成绩,存入数组a的第i个位置
    }
    
    // 第二个循环:核心合并过程,执行n-1次合并
    for(int i = 0; i < n-1; i++) {   // 循环n-1次(因为需要将n个数合并成1个数)
        sort(a + i, a + n);           // 对数组从索引i到n-1的部分进行升序排序
                                      // 确保每次合并的都是当前最小的两个数
        
        add = a[i] + a[i+1];     // 将当前最小的两个数相加(a[i]和a[i+1]是排序后的最小两个)
        a[i+1] = add;            // 将合并结果存入a[i+1]位置(覆盖原来的值)
        sum += add;              // 将本次合并的和累加到sum中
        
        // 注意:a[i]的值虽然没变,但下次循环时i增加,这个值就不再被使用了
        // 相当于每次合并后,有效数据范围从[i, n-1]变成了[i+1, n-1]
    }
    
    cout << sum;            // 输出所有合并操作的总和
    return 0;              
}
相关推荐
旺仔仔仔17 分钟前
机器人项目实战(5):从单次抓取,到接收指令连续做事
算法
旺仔仔仔26 分钟前
机器人项目实战(2):识别物体、提取点云,再到抓取姿态
算法
姜鱼问生28 分钟前
密码明明一样,为什么 GPG 说“错的“?
后端·算法·架构
启观川42 分钟前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
对空六课1 小时前
指标口径生效时间的版本查询实现
大数据·服务器·前端·算法·数据分析
对空六课1 小时前
RFM分层边界变化的回溯计算
大数据·服务器·前端·数据库·人工智能·算法·数据分析
一勺思维1 小时前
我为什么把 Agent 的核心逻辑从 LangChain 里搬出来手写
算法
碧海银沙音频科技研究院1 小时前
基于炬芯ATS308X的LE aduio LC3编解码算法功能实现
算法
小蒋观天下1 小时前
厂区人员徘徊游荡判别——基于时序轨迹速度的逗留行为分级算法落地
大数据·人工智能·深度学习·算法·机器学习·ai大模型
程序员清风2 小时前
堆与优先队列:从 Top K 到任务调度
java·数据结构·算法