计算机保研机试准备——C++算法题(二)
第一篇:基础题
计算机保研机试准备——C++算法题(一)_计算机保研机试题单-CSDN博客文章浏览阅读643次,点赞4次,收藏4次。记录C++算法刷题,准备机试_计算机保研机试题单https://blog.csdn.net/weixin_47520540/article/details/147255264?sharetype=blogdetail&sharerId=147255264&sharerefer=PC&sharesource=weixin_47520540&spm=1011.2480.3001.8118
四、函数递归题
(15)P4994 终于结束的起点
题目概括:
/*
#include<bits/stdc++.h>
using namespace std;int f[10000001];//尽可能大
int main() {int m;cin >> m;f[0] = 0;f[1] = 1;for (int i = 2; i < 10000001; i++) {f[i] = (f[i - 1] + f[i - 2]) % m;}int res = 0;for (int i = 1; i < 10000000; i++) {if (f[i] == 0 && f[i + 1] == 1) {res = i;break;}}cout << res;return 0;
}
*/#include<bits/stdc++.h>
using namespace std;
int main(){int m;cin >> m;int a = 0, b = 1, c;int i = 0;while(true){c = (a+b)%m;a = b;b = c;i++;if(a==0&&b==1)break ;}cout << i;return 0;}
(16)P1025 [NOIP 2001 提高组] 数的划分
题目概括
给定整数 \( n \)(\( 6 < n \leq 200 \))和 \( k \)(\( 2 \leq k \leq 6 \)),求将 \( n \) 分成 \( k \) 个不为空且不考虑顺序的不同分法的数量。
DFS+剪枝(减少重复)
// DFS+剪枝(减少重复)
#include<bits/stdc++.h>
using namespace std;//三个变量:num(剩余待分的整数),part(剩余分的份数,初始为k),start(当前要选择的数的最小值,初始为1) 注:每次选择一个数后,下一个数的选择从当前数开始,以避免重复分法
int dfs(int num,int part,int start){//首先特殊情况if(part==1) return 1;int sum = 0;// 当前选择的数不能超过num/part,是一种剪枝操作,比如(6,2,1)时i<=3,i会有1、2、3中情况,但i=4时,剩余1份分配为2,这与前面的i=2,剩4重复了for(int i =start; i<= num/part;i++){sum += dfs(num-i,part-1,i);}return sum;
}int main(){int n,k;cin >> n >>k;cout <<dfs(n,k,1)<<endl;return 0;
}
动态规划(递推)
//动态规划(递推)
//dp[i][j] :将i分成j份的种类数
//因为6<n,k>=6,所以每份至少为1
#include<bits/stdc++.h>
using namespace std;
int dp[201][6];int main(){int n,k;cin >> n>>k;//初始化for(int i=1;i<=n;i++){dp[i][1] = 1;}for(int i =2;i<=n;i++){for(int j = 2;j<=k;j++)//dp[i-1][j-1] 表示组合中含1(当前),dp[i-j][j] 表示不含1,理解为先为j都分配1,故等价于i-j再分j份(每份>1) " if(i>=j)"一定要写if(i>=j) dp[i][j] = dp[i-1][j-1] + dp[i-j][j];}cout <<dp[n][k];return 0;
}
(17)P1192 台阶问题
有 N 级台阶,你一开始在底部,每次可以向上迈 1∼K 级台阶,问到达第 N 级台阶有多少种不同方式。
//斐波那契数列思想,这道题的基础版:https://zhaotong.fun/2022/06/15/dynamic-programing.html// class Solution {
// public:
// int climbStairs(int n) {
// vector<int>dp(n+1);
// dp[1]=1;
// dp[0]=1;
// for(int i =2;i<=n;i++){
// dp[i] = dp[i-1]+dp[i-2];
// }
// return dp[n];
// }
// };#include<bits/stdc++.h>
using namespace std;
const int mod = 100003;
int n,k,dp[100001];
int main(){cin >> n>>k;dp[0] = dp[1]=1;for(int i =2;i<=n;i++){for(int j=1;j<=k;j++){if(i>=j){dp[i] = (dp[i]+dp[i-j])%mod; //dp[i-k]从第 i−k级台阶迈k级到达第 i 级台阶的所有可能方式,累加形式(不除模的话可以写成dp[i]+=dp[i-j])}}}cout << dp[n]%mod;return 0;
}
(18)P1464 Function
实现递归函数 \(w(a,b,c)\),按给定条件(如 \(a,b,c \leq0\) 或 \(>20\) 等不同情况的返回规则)计算结果,需优化以应对重复调用问题,多组输入(以 \(-1,-1,-1\) 结束),输出格式为 \(w(a, b, c) = ans\)。
//记忆化减少重复
#include<bits/stdc++.h>
using namespace std;
//定义数组储存计算过的数,21是因为>20的返回w(20,20,20)
int w[21][21][21]; //已经计算过的 w(a, b, c) 的值
bool v[21][21][21];//标记 w(a, b, c) 是否已经被计算过,true则返回w[a][b][c]
//w[n][m][z],v[n][m][z]初始为 0和false
int f(long long a,long long b,long long c){ //f计算w(a,b,c)的值if(a<=0 or b<=0 or c<=0) return 1;if(a>20 or b>20 or c>20) return f(20,20,20);if(v[a][b][c]) return w[a][b][c]; //计算过则直接取值if(a<b & b<c){w[a][b][c] = f(a,b,c-1)+f(a,b-1,c-1)-f(a,b-1,c);}else{w[a][b][c] = f(a-1,b,c)+f(a-1,b-1,c)+f(a-1,b,c-1)-f(a-1,b-1,c-1);}v[a][b][c] = true; //标记return w[a][b][c];
}
int main(){long long a,b,c;// scanf("%lld %lld %lld",&a,&b,&c); //为了判断第一次a,b,c能否进入循环// while(a!=-1 or b!=-1 or c!=-1){// printf("w(%lld, %lld, %lld) = %d\n",a,b,c,f(a,b,c));// scanf("%lld %lld %lld",&a,&b,&c);// } while(1){cin >>a>>b>>c;if(a==-1 & b==-1&c==-1) return 0;cout << "w("<<a<<", "<<b<<", "<<c<<")"<<" = "<<f(a,b,c) <<endl;}
}
(19)P5534 【XR-3】等差数列
给定等差数列的前两项 \(a_1\)、\(a_2\) 以及项数 n,求该等差数列的各项之和。
//直接上求和公式
#include<bits/stdc++.h>
using namespace std;
int main(){long a,b,n,c;cin >> a>>b>>n;c= b-a;cout << a*n +n*(n-1)*c/2;
}
(20)P1036 [NOIP 2002 普及组] 选数
给定 \( n \) 个整数和整数 \( k \)(\( k < n \)),计算从这 \( n \) 个数中选 \( k \) 个相加,和为素数的组合种数。
//组合题+素数,全排列题目见P1706
#include<bits/stdc++.h>
using namespace std;
int m,k,res=0;
int nums[21];
//判素数
bool isprime(int n){if(n<2) return false;for(int i=2;i<=sqrt(n);i++){if(n%i==0) return false;}return true;
}//DFS s为搜索起始位置,cut为已选取的个数 sum为选取数的和
void dfs(int s,int cut,int sum){if(cut == k){if(isprime(sum)){res ++;}}for(int i=s;i<m;i++){dfs(i+1,cut+1,sum+nums[i]);}
}
//主函数
int main(){cin >> m>> k;for(int i=0;i<m;i++){cin >> nums[i];}dfs(0,0,0);cout << res<<endl;return 0;
}
(21)P1028 [NOIP 2001 普及组] 数的计算
给定正整数 \( n \),构造合法数列:单个 \( n \) 是合法数列;合法数列末尾可加不超过最后一项一半的正整数生成新合法数列。求合法数列的总个数。
//动态规划思想
#include<bits/stdc++.h>
using namespace std;
int nums[1001];
//核心:理解nums[i]的含义->以i为结尾的合法数列的总数(注意是总数)
int main(){int n;cin >> n;// 对于每个 i,尝试所有可能的 j(可以添加到 i 后面的数字)for(int i=1;i<=n;i++){//j从1开始(题目要求正整数) for(int j=1;j<=i/2;j++){nums[i] += nums[j]; // 将 j 的合法数列数量累加到 i 的总数中}nums[i] ++; // i自身单独成数列的情况}cout << nums[n];return 0;
}