2024蓝桥杯——宝石问题

news2024/11/28 22:38:54

先展示题目

声明

以下代码仅是我的个人看法,在自己考试过程中的优化版,本人考试就踩了很多坑,我会—一列举出来。代码可能很多,但是总体时间复杂度不高只有0(N²)

函数里面的动态数组我没有写开辟判断和free,这里我忽略掉了。

正文

先直接抛出最后的代码:

 

我也觉得太长了,大家可以当做知识点的掌握来看吧。

从数据中取出n个数的问题-->可以拓展到取出所有子集问题

先讲子集问题

这个问题我们可以用三个for循环来做,但是时间复杂度太高了。所以我们有以下的方法。

一个数取不取就有两种情况。我们可以用0或1来表示。那么我们就可以用二进制来表示我们的取或不取,用每位二进制的位置来对于每个元素。

例如:有1 2 两个数字。我们就可以用两位二进制来表示:00 01 10 11分别表示 不取任何数 取2 取1 都取。一共有2^2次方中情况

那么我们推广到n,就有2^n种。

我们来尝试写一下代码。

直接用二进制

完全没问题。

用数组模拟二进制

这里有一个问题不知道大家看到没:2^n 容易溢出。因此我们可以用数组来模拟二进制的自增。

自增问题涉及到进一问题,所以我们需要运用到递归,递归的判断终止条件就是n+1位由0变成1。

所以我们需要开辟n+1长度的数组nums。

用类似递归来实现
用循环(最优解)

这里几个continue和return一定要有,不然逻辑就错了

这样的话我们就可以遍历任何长度的数组的子集了!

下面把代码给大家

#include<stdio.h>
#include<stdlib.h>

void nums_add(int* arr, int len) {
    if (len == 1) {
        *arr = 1;
        return;
    }
    else if (*arr == 1) {
        *arr = 0;//加一后变成零了
        nums_add(arr + 1, len - 1);//让后面一位加一,然后剩余长度减一
    }
    else if(*arr==0){
        *arr=1;//0加成1
    }
}

void nums_add_(int* arr, int len) {
    int k = len,i=0;
    while (1) {
        if (k == 1) {
            arr[i] = 1;//如果长度为1了就退出
            return;
        }
        if (arr[i] == 1) {
            arr[i] = 0;
            ++i;
            --k;
            continue;//如果要进一我们还要循环一次,所以用continue
        }
        else if (arr[i] == 0) {
            arr[i] = 1;
        }
        return;//到这里表示从0加到一,我们就不需要再循环了,直接结束循环
    }
}
int main() {
    int n = 0;
    scanf("%d", &n);
    int* arr = (int*)malloc(n * sizeof(int));
    if (!arr)return -1;
    for (int x = 0; x < n; ++x) {
        scanf("%d", arr + x);
    }

    int* nums = (int*)calloc(n+1, sizeof(int));
    int m[3];
    while (1) {
        nums_add_(nums, n + 1);
        if (nums[n] == 1)break;
        int k = 0;
        for (int x = 0; x < n; ++x) {
            if (nums[x] == 1)
            {
                if (k == 3)break;//已经有三个了还要存,直接跳过这个
                m[k++] = arr[x];
            }
        }
        if (k!=3)continue;//如果不等于三个,直接跳过到下一个循环
        printf("%d %d %d",m[0],m[1],m[2]);
        printf("\n");
    }
    return 0;
}

因为递归会开辟内存,所以后面的代码我们都用第二种非递归的

取出长度固定的所有子集

如果我们只要里面长度为3的子集怎么办呢?

自增变量来判断

我们可以在for循环里面先用一个长度为三的数组来存储我们的数据,再用一个变量来看是否满足。满足就打印。

在递归/非递归的时候就检测好

递归的时候我们完全就可以把1的数量统计好,所以可以做以下改变

但是这样也没怎么变化嘛,那么我们既然可以知道1了,我们再储存一下有1的数组的位置可以吧?

这里我们发现是反着来的,我们把打印的顺序反过来就行了。因为这里的m数组相当于栈

#include<stdio.h>
#include<stdlib.h>

void nums_add(int* begain_arr, int* arr, int* m, int* p, int len, int* number) {
    if (len == 1) {
        *arr = 1;
        return;
    }
    else if (*arr == 1) {
        *arr = 0;//加一后变成零了
        --(*number);
        if (*p>0) {
            --p;
        }
        nums_add(arr,arr + 1,m,p, len - 1,number);//让后面一位加一,然后剩余长度减一
    }
    else if(*arr==0){
        ++(*number);
        *arr=1;//0加成1
        if (*p < 3) {
            m[(*p)++] = (int)(arr - begain_arr);
        }
    }
}

void nums_add_(int* arr,int*m,int *p,int len, int*number) {
    int k = len,i=0;
    while (1) {
        if (k == 1) {
            arr[i] = 1;//如果长度为1了就退出
            return;
        }
        if (arr[i] == 1) {
            arr[i] = 0;
            --(*number);
            ++i;
            --k;
            if (*p>0) {
                --(*p);
            }
            continue;//如果要进一我们还要循环一次,所以用continue
        }
        else if (arr[i] == 0) {
            arr[i] = 1;
            ++(*number);
            if (*p < 3) {
                m[(*p)++] =i;
            }
        }
        return;//到这里表示从0加到一,我们就不需要再循环了,直接结束循环
    }
}
int A_(int m, int n) {//非递归型
    int k = 1, i = m, j = n;
    while (1) {
        if (i == 1)return k * j;
        else {
            k *= j;
            --i;
            --j;
        }
    }
}
int C_(int m, int n) {
    return m == 0 ? 1 : A_(m, n) / A_(m, m);
}
int main() {
    int n = 0;
    scanf("%d", &n);
    int* arr = (int*)malloc(n * sizeof(int));
    if (!arr)return -1;
    for (int x = 0; x < n; ++x) {
        scanf("%d", arr + x);
    }

    int* nums = (int*)calloc(n+1, sizeof(int));
    int m[3] , p = 0 , number1 = 0;//定义number1存储我们的1的数量
    while (1) {
        nums_add_(nums,m,&p, n + 1, &number1);
        if (nums[n] == 1)break;
        int k = 0;
        if (number1 != 3)continue;
        printf("%d %d %d",m[2],m[1],m[0]);
        printf("\n");
    }
    return 0;
}

那么我们第一部分终于也是完成了,我嘞个豆真是多!!!!!!!!!!!!!!!!!!!!!!!!!

a,b的最小公倍数和最大公约数

我们题目要求的是最小公倍数,那么求这个我们可以枚举,但是时间复杂度复很高,所以我们就有特殊的算法。

我们首先要了解一个知识点就是

a*b=最大公约数(a,b)*最小公倍数(a,b)

我们求最小公倍数可能没有优秀的算法,但是我们最大公约数有优秀的算法。那么就可以通过这个式子进行转化。

辗转相除法求最大公约数

举个例子:求16 和 24的最大公约数

                24%16 =8

                16%8 = 0

                所以答案是8 

如果开始两个数字交换呢?

                16%24=16

                24%16=8 

                16%8=0

我们发现就是多了一部,没有太大差别。

那么我们开始实现

这里return的是最大公约数。

如果求三者的最大公约数或者最小公倍数,把其中两个数的先求出来,再看成整体和另一个求。

S

那么图中的表达式我们就可以算了

这里同样的,先除法再乘法,防止溢出了。

创建二维数组来存储三个都是1的数据。

我们就要用一个二维数组来储存我们的数据。那么每一个数组的长度是多少呢?

根据组合数我们要C(3,n)长度。排列组合在编程里面也很常见,我们也要知道他是怎么算出来的,排列组合我在下面讲到

排列组合函数

先是讲A(m,n)

如果m=n,那么就是算的阶乘。

我们可以通过A(m,n)=A(m-1,n-1)*n   来计算

C(m,n)

它有两个公式可以算,一个是C(m,n)=A(m,n)/A(n,n)  另一个是C(m,n)=n!/m!/(n-m)!

那么那个好呢?当然是第一个,第一个数字间相乘的次数少,不容易溢出。

储存后方便我们后面再取。

我们再用一个变量来存储S的最大值

那么我们的宝石问题就完成了。

真的完成了吗?

no no no

存储根本不需要二维数组,我写到这才发现,我们只要用一个长度为3个数组来储存最大的数据就行了

那么我们的排列组合函数就不需要了。

另外补充

我们m数组的长度定义的太短了,会产生越界访问。所以可以将m数组的长度定义长一点。可以和arr的数组一样长.

提前排序来解决字典序要求

我们的代码已经可以计算了,但是还有最后一个坑。例如我们逆向输入

因为S(5,4,3)和S(1,2,3)的值是一样的,所以我们不会存后面字典序小的数据。我们最要先将数据进行排序。

这里我们光速搓一个快排出来

在计算之前排好序就行了。

最终的代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1599150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业网站建设需要了解什么

在现代商业环境中&#xff0c;企业网站已经成为企业宣传、推广和销售的重要工具。企业网站的建设需要考虑多个因素&#xff0c;包括以下几个方面&#xff1a; 首先&#xff0c;了解企业的目标和定位。企业网站的建设应该围绕企业的目标和定位展开&#xff0c;以达到企业在市场中…

基于python的景点舆情分析,爬虫获取景点数据,评论数据,情感分析和可视化展示

概述 毕业设计项目中&#xff0c;构建一个基于Python的系统&#xff0c;用于抓取携程网上的江西省景点信息及对应评论数据&#xff0c;并进行深入的舆情分析。 数据获取&#xff1a; 使用Python的requests库模拟浏览器发送HTTP请求至指定URL&#xff08;https://m.ctrip.com/r…

HW机试1

1.字符串翻转函数 string s;reverse(s.begin(),s.end()); 2.不区分大小写统计字符出现的个数 需要判断是大小写字母。根据ASCII码值&#xff0c;大写字母32小写字母 void func(string s,char ch) {int lens.length(),cnt0;if(ch>64){for(int i0;i<len;i){if(s[i]32ch…

用户相关的配置文件

1.新建用户的配置文件从哪里来的&#xff1f; 在Linux操作系统中都有一个默认行为&#xff0c;当在Linux操作系统中新建用户时&#xff0c;都会在/home/用户名 也就是新建用户的家目录中配置三个隐藏文件 分别是.bash-logout .bash-profile .bashrc 如上图所示&#xff…

解决WPS右键菜单冗余选项,去除WPS右键菜单选项

问题描述 安装WPS后&#xff0c;右键菜单会多出许多无用的选项&#xff0c;如何去除&#xff1f; 解决方法 按下WindowsS打开搜索栏&#xff0c;搜索配置工具打开 勾选所有的关闭和隐藏选项

通过Maven导入本地jar包

1.创建lib文件夹&#xff0c;把jar包放到文件夹里面 2.在pom里导入依赖 导入完成

AI数字人对话之RealChar框架源码解读

零.功能介绍 与虚拟角色(非形象)进行文本或语音会话 体验地址:RealChar. 代码库:GitHub - Shaunwei/RealChar: 🎙️🤖Create, Customize and Talk to your AI Character/Companion in Realtime (All in One Codebase!). Have a natural seamless conversation with AI…

2024年nodejs调用小红书最新关注(粉丝)follow接口,api接口分析2004-04-16

一、打开chrome按f12&#xff0c;点击右上角的“关注”按钮&#xff0c;抓包位置如下&#xff1a; (图1 follow接口) 二、follow接口分析 1、请求地址 https://edith.xiaohongshu.com/api/sns/web/v1/user/follow 2、请求方法: POST 3、请求头&#xff1a; :authority: edith…

【绘图案例-带圆环的图片-图片 Objective-C语言】

一、接下来,我们接着来说,带圆环的图片,图片, 1.我们还差这个,图片,啊, 图片还没有画上去啊,圆环已经画完了, 接下来呢,我们应该尝试着去画图片, // 12.画图片 image drawAtPoint:(CGPoint) 如果我直接这么着去画的话, 那么,实际上,就会把那个方形的东西,…

Linux Shell Script 编程详解

1. Shell Script入门介绍 1.1 什么是Shell Shell 是指一种应用程序&#xff0c;它是用户使用 Linux 的桥梁&#xff0c;这个应用程序提供了一个界面&#xff0c;用户通过这个界面访问操作系统内核的服务。Shell 脚本&#xff08;shell script&#xff09;&#xff0c;是一种为…

移动端web适配方案

以下是移动端适配的多个方案&#xff0c;也可以说说你是怎么做的。 正文 自适应&#xff1a;根据不同的设备屏幕大小来自动调整尺寸、大小 响应式&#xff1a;会随着屏幕的实时变动而自动调整&#xff0c;是一种更强的自适应 为什么要做移动端适配&#xff1f; 目前市面上…

亚马逊云科技数据工程师考试官方免费课程上线啦

自从上次小李哥分享了AWS Data Engineer Associate证书首通经验后&#xff0c;有非常多的小伙伴们问我&#xff0c;应该怎么复习这门考试呢&#xff1f; 这门考试是AWS针对最近大热&#x1f525;的AI、数据分析、数据科学等行业&#xff0c;推出的全新考试。因为刚刚推出&#…

JavaEE > > Spring(1)

Spring Spring&#xff1a;包含众多方法的 IoC 容器.&#xff0c;是一个集成很多方法的框架,让应用程序开发更加简单. IoC&#xff1a;Inversion of Control 翻译成中⽂是“控制反转”的意思. 这是一个设计思想&#xff0c;而不是一个具体的实现方式.该思想就是把原本在程序中…

海外云手机为什么适合社媒运营?

如今&#xff0c;社媒营销如果做得好&#xff0c;引流效果好的账号&#xff0c;可以用来带货变现&#xff0c;而外贸、品牌出海也同样都在做社媒营销&#xff0c;Tik Tok、facebook、ins等热门的海外社媒平台都是行业密切关注的&#xff0c;必要的时候&#xff0c;大家会使用海…

区块链实验室(35) - 编译solana for ARM64版

今天终于成功编译solana for arm64版&#xff0c;编译时间巨长。见下图所示。编译步骤详见solana网站https://github.com/solana-labs/solana和https://docs.solanalabs.com/。

ORA-00742 ORA-00312 恢复---惜分飞

有客户反馈,断电之后数据库启动报ORA-00742和ORA-00312,无法正常open 我们远程上去尝试open库结果也报同样错误 [oracleoldhis oradata]$ sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on Wed Apr 10 09:40:03 2024 Copyright (c) 1982, 2013, Oracle. A…

计算机网络(五)传输层

传输层 从通信和信息处理的角度看&#xff0c;传输层向它上面的应用层提供通信服务&#xff0c;属于面向通信部分的最高层&#xff0c;同时也是用户功能中的最低层 传输层功能&#xff1a; 传输层提供应用进程之间的逻辑通信(即端到端的通信)。与网络层的区别区别是&#xf…

MySQL 试图

视图功能在 5.0 以后的版本启用 视图是一张虚表。数据表确实包含了具体数据并且保存到硬盘中的实表。视图使用数据检索语句动态生 成的一张虚表。每一次数据服务重启或者系统重启之后&#xff0c;在数据库服务启动期间&#xff0c;会使用创建视图的语 句重新生成视图中的数据&…

揭秘智慧礼品背后的故事

如若不是从事技术行业&#xff0c;在罗列礼品清单时&#xff0c;可能不会想到 “数据”&#xff0c;但幸运的是&#xff0c;我们想到了。如何将AI技术应用到当季一些最受青睐的产品中去&#xff0c;训练数据是这一智能技术的背后动力。很多电子设备或名称中带有“智能”一词的设…

频率域滤波总结

我本来想写在一起的&#xff0c;但是这样的话就没有重点了。分开写更能总结出来问题。这里的步骤5的对称滤波函数确实是(2M-1)x(2N-1)的大小&#xff0c;但是书上还说了如下图所示的问题: 首先第一个问题是乘积的问题&#xff0c;为什么普通的函数乘积也需要填充零&#xff1f;…