备战蓝桥杯(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;              
}
相关推荐
song8546011342 小时前
hash和history导航区别 个别服务器为啥不支持 history 模式
服务器·算法·哈希算法
IT猿手2 小时前
多无人机动态避障路径规划研究:基于粒子群优化算法PSO的多无人机动态避障路径规划研究(可以自定义无人机数量及起始点),MATLAB代码
算法·matlab·机器人·无人机·路径规划·动态路径规划
MoonBit月兔2 小时前
MoonBit 0.8.3版本更新
开发语言·人工智能·算法·ai编程·moonbit
xsyaaaan2 小时前
leetcode-hot100-哈希表:1两数之和-49字母异位词分组-128最长连续序列
算法·leetcode·散列表
小此方2 小时前
Re:从零开始的 C++ 进阶篇(二)C++继承到底做了什么?从对象模型到底层内存布局彻底讲透
c语言·开发语言·c++
zmzb01032 小时前
C++课后习题训练记录Day114
开发语言·c++
柏木乃一2 小时前
Linux线程(2)线程的优点和缺点/线程异常/posix线程库原理
linux·运维·服务器·c++·线程·posix
代码探秘者2 小时前
【Redis】双写一致性:延迟双删 / 读写锁 / 异步通知 / Canal,一文全解
java·数据库·redis·后端·算法·缓存
小指纹2 小时前
2026牛客寒假算法基础集训营1
算法·macos·cocoa