目录
一.砝码称重
你有一架天平和 N个砝码,这 N个砝码重量依次是 W_1, W_2, · · · , W_N
请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数 N。第二行包含 N 个整数:W_1, W_2, W_3, · · · , W_N
输出格式
输出一个整数代表答案。
答案参考:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N;
ll a[200];
ll summ=0;
ll ans=0;
int dp[200][200000];
//dp[i][j]表示用到前i个砝码,能否称出j重量
//1为可以,0为不可以
int main()
{
// 请在此输入您的代码
cin>>N;
for(int i=1;i<=N;i++){
cin>>a[i];
summ+=a[i];
}
for(int i=1;i<=N;i++){
for(int j=1;j<=summ;j++){//遍历所有可能的重量
dp[i][j]=dp[i-1][j];//继承前一个状态
if(dp[i][j]==0){//如果普通继承下来,发现这个不行呢?
if(j==a[i]) dp[i][j]=1;//如果需要的重量正好就是第i个砝码,那么可以
if(dp[i-1][j+a[i]]==1) dp[i][j]=1;//如果前i-1个能搞出j+a[i]重量,那么把第i个砝码放到另一侧就行
if(dp[i-1][abs(j-a[i])]==1) dp[i][j]=1;//如果前i-1个砝码能搞出abs(j-a[i])重量
//那么把第i个砝码放同侧就行
}
}
}
for(int j=1;j<=summ;j++){
if(dp[N][j]==1) ans++;//遍历,看dp[][]==1的个数,就是答案
}
cout<<ans<<endl;
return 0;
}
二.乘积最大
今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡
江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活
动的选手出了这样一道题目:
设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:
有一个数字串:312, 当N=3,K=1时会有以下两种分法:
3*12=36
31*2=62这时,符合题目要求的结果是:31*2=62
现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。
输入格式
程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。
输出格式输出所求得的最大乘积(一个自然数)。
样例输入
4 2
1231样例 输出:
62
答案参考:
#include <stdio.h>
#include <string.h>
#define N_MAX 40
#define K_MAX 6
//首先,在代码中我们定义了一个 `getValue` 函数,该函数用于获取数字串中指定位置范围内的数字的值。
//通过循环遍历指定范围内的字符,并将其转换为整数,然后以十进制形式构建数字。
int getValue(char* digits, int start, int end) {
int value = 0;
for (int i = start; i <= end; i++) {
value = value * 10 + (digits[i] - '0');
}
return value;
}
//接下来,我们使用动态规划的方法来解决问题。我们定义一个二维数组 `dp[N_MAX][K_MAX]`,其中 `dp[i][j]`
//表示将数字串从位置 0 到位置 i 分为 j+1 个部分所得到的最大乘积。动态规划的关键在于找到问题的状态转移方程。
long long int maxValue(char* digits, int N, int K) {
long long int dp[N_MAX][K_MAX];
memset(dp, 0, sizeof(dp));
//我们先初始化第一行 `dp[0][j]`,它们的值分别为数字串从位置 0 到位置 j 的数字。然后,我们从第二行开始逐行填充数组。
for (int i = 0; i < N; i++) {
dp[i][0] = getValue(digits, 0, i);
}
//对于每个位置 `(i, k)`,我们需要考虑将数字串从位置 `(k+1, i)` 分割成 j+1 个部分的情况。我们使用一个三层循环。
//外层循环遍历每个 k,表示可能的最后一个乘号的位置,中间层循环遍历 k 之前的位置 j,内层循环遍历 k+1 到 i 之间的位置 p。
for (int k = 1; k <= K; k++) {
for (int i = k; i < N; i++) {
for (int j = k - 1; j < i; j++) {
long long int product = dp[j][k - 1] * getValue(digits, j + 1, i);
if (product > dp[i][k]) {
dp[i][k] = product;
}
}
}
}
return dp[N - 1][K];
}
//在每轮循环中,我们计算将数字串从位置 `(p+1, i)` 分割成 j 个部分的最大乘积 `dp[p][j-1]`,并与数字串从位置 `(j+1, i)`
//分割为一个部分的乘积 `getValue(digits, j+1, i)` 相乘得到新的乘积。如果这个新的乘积大于 `dp
int main() {
int N, K;
char digits[N_MAX + 1];
scanf("%d %d", &N, &K);
scanf("%s", digits);
long long int result = maxValue(digits, N, K);
printf("%lld\n", result);
return 0;
}
三.七段码
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小蓝要用七段码数码管来表示一种特殊的文字。
上图给出了七段码数码管的一个图示,数码管中一共有 77 段可以发光的二 极管,分别标记为 a, b, c, d, e, f, ga,b,c,d,e,f,g。小蓝要选择一部分二极管(至少要有一个)发光来表达字符。在设计字符 的表达时,要求所有发光的二极管是连成一片的。
例如:bb 发光,其他二极管不发光可以用来表达一种字符。
例如 cc 发光,其他二极管不发光可以用来表达一种字符。这种方案与上 一行的方案可以用来表示不同的字符,尽管看上去比较相似。
例如:a, b, c, d, ea,b,c,d,e 发光,f, gf,g 不发光可以用来表达一种字符。
例如:b, fb,f 发光,其他二极管不发光则不能用来表达一种字符,因为发光 的二极管没有连成一片。
请问,小蓝可以用七段码数码管表达多少种不同的字符?
答案参考:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int ans = 0;
for(int a = 0 ; a <= 1 ; a++){
for(int b = 0 ; b <= 1 ; b++){
for(int c = 0 ; c <= 1 ; c++){
for(int d = 0 ; d <= 1 ; d++){
for(int e = 0 ; e <= 1 ; e++){
for(int f = 0 ; f <= 1 ; f++){
for(int g = 0 ; g <= 1 ; g++){
int s = a + b + c + d + e + f + g;
if(s == 1){
ans++;
}
if(s >= 2){
//当相连的二极管任何一个都是不亮时continue
if(a == 1 && f ==0 && b ==0){
continue;
}
else if(b == 1 && a == 0 && g ==0 && c == 0){
continue;
}
else if(c == 1 && b == 0 && g == 0 && d == 0){
continue;
}
else if(d == 1 && e == 0 && c == 0){
continue;
}
else if(e == 1 && f == 0 && g == 0 && d == 0){
continue;
}
else if(f == 1 && a == 0 && g == 0 && e == 0){
continue;
}
else if(g == 1 && f == 0 && b == 0 && e == 0 && c== 0){
continue;
}
ans++;
}
}
}
}
}
}
}
}
//结果-3 是因为当二极管两两成组的时候有3种不是连起来的情况:ab与ed,af与cd,ef与cb
printf("%d",ans-3);
// 请在此输入您的代码
return 0;
}
持续更新......
有帮助请来个👍喔!