从零开始的蓝桥杯(一)

目录

一.进制问题

1.十进制转二进制

同理:十进制转八进制(把取余数的和除数都改成8就 欧克了)

2.十进制转十六进制(特殊的)

3.二进制转十进制

同理八进制转十进制:就是把term 的改变换成乘以8罢了

4.十六进制转十进制(同样是字母的问题,同样使用分支结构解决)

5.二进制转八进制

6.二进制转十六进制

7.八进制转二进制

8.十六进制转二进制

9.十六进制转八进制

10.八进制转十六进制

11.最小的十六进制

二.范围覆盖问题(Flood Fill)

0.知识点

1.清理水草

2.信号覆盖

3.最大连通分块

连通分块变式题目

优化另解:

4.最长滑行

5.池塘计数(简单套用)

7.山峰和山谷

8.迷宫问题


一.进制问题

1.十进制转二进制

除2取余数得最低1位,然后把商继续除得第2位,直到商等于0(这里用循环实现)
 

#include <iostream>

using namespace std;

int main()
{
    int num;
    cin>>num;
    int str[1000];
    int i = 0;
    while(num>0){
        str[i++] = num%2;
        num /= 2;
    }
    for(int j=i-1;j>=0;j--)
    cout << str[j];
    return 0;
}

这里需要注意的是要用int 整型数组来存储值,否则打印出来的不是数字字符了

用   ‘0’ + xxx 可以解决这个问题

#include <iostream>

using namespace std;

int main()
{
    int num;
    cin>>num;
    char str[1000];
    int i = 0;
    while(num>0){
        str[i++] = '0'+num%2;
        num /= 2;
    }
    for(int j=i-1;j>=0;j--)
    cout << str[j];
    return 0;
}

同理:
十进制转八进制(把取余数的和除数都改成8就 欧克了)

#include <iostream>

using namespace std;

int main()
{
    int num;
    cin>>num;
    char str[1000];
    int i = 0;
    while(num>0){
        str[i++] = '0'+num%8;
        num /= 8;
    }
    for(int j=i-1;j>=0;j--)
    cout << str[j];
    return 0;
}

什么九进制,七进制啥的都只用改变除数和取余的数即可!!!

2.十进制转十六进制(特殊的)

特殊在于:需要表示的还有字母,因此要用分支结构来分类讨论

#include <iostream>

using namespace std;

int main()
{
    int num;
    cin>>num;
    char str[1000];
    int i = 0;
    int ch;
    while(num>0){
        ch = num%16;
        if(ch>9){
            str[i++] = 'a'+ch-10;
        }
        else str[i++] = '0'+ch;
        num /= 16;
    }
    for(int j=i-1; j>=0; j--)
        cout << str[j];
    return 0;
}

同样适用于如十二进制,十八进制之类的转换

3.二进制转十进制

也就是每一位的 0 或 1 乘上 2的多少次方吧 (可以用pow()函数来计算)

也可以用一个 int  term = 1 ; 每次都将ret 乘以一个2来进行更新!!!

值得注意的是:输入的二进制数可能太长不能用long long 保存

还是用char 数组更加保险,然后这里要记得强制类型转换(int),还有要从后往前计算!!!

#include <iostream>

using namespace std;

int main()
{
    char num[100];
    gets(num);
    int term = 1;
    int ret = 0;
    int i = 0;
    while(num[i]) i++;
    while(i>0){
        ret += ((int)num[--i]-48)*term;
        term *= 2;
    }
    cout << ret;
    return 0;
}

同理八进制转十进制:就是把term 的改变换成乘以8罢了

#include <iostream>

using namespace std;

int main()
{
    char num[100];
    gets(num);
    int term = 1;
    int ret = 0;
    int i = 0;
    while(num[i]) i++;
    while(i>0){
        ret += ((int)num[--i]-48)*term;
        term *= 8;
    }
    cout << ret;
    return 0;
}

4.十六进制转十进制(同样是字母的问题,同样使用分支结构解决)

#include <iostream>

using namespace std;

int main()
{
    char num[100];
    gets(num);
    int term = 1;
    int ret = 0;
    int i = 0;
    while(num[i]) i++;
    int ch;
    while(i>0){
        ch = (int)num[--i];
        if(ch>='a' && ch<='z')
            ret += (ch-87)*term;
        else if(ch>='A' && ch<='Z')
            ret += (ch-55)*term;
        else
            ret += (ch-48)*term;
        term *= 16;
    }
    cout << ret;
    return 0;
}

这样子管他十二进制还是十八进制都可以用了(只用改变一下term 的迭代方程)

5.二进制转八进制

(一种思路是用十进制作为媒介,二到十到八,不过可能会有误差)

另外一种思路是:

        从二进制到八进制就是每三个数字一组转化为一个八进制元素!!!

#include <iostream>

using namespace std;

int main()
{
    char num[100];
    int str[100] = {0};
    gets(num);
    int term = 1;
    int div = 1;
    int i = 0;
    int j = 0;
    int flag = 0;
    while(num[i]) i++;
    while(i>0){
        if(flag==3){
            str[j] /= div;
            j++;
            flag = 0;
            div *= 8;
        }
        str[j] += term*((int)num[--i]-48);
        term *= 2;
        flag++;
    }
    if(flag!=3) str[j] /= div;
    for(int k = j;k>=0;k--)
    cout << str[k];
    return 0;
}

这里有几个细节点:
str 用的是整型数组,并且一定要初始化为0

div 是除数,用于将每一项的数进行八进制化(其实就是利用了二转十再转八的思想)

每一项最后都要除以div,其中有可能首项由于没有凑满三项二进制数相加,因而没有进行相除操作,所以在跳出循环后,还要特地对首项进行一次操作

然后此处运用 flag 标志来实现三个为一组的运算!!!(里面的重置与迭代也很关键)

对于二进制转其他比如五进制,九进制啥的,还是用二转十,十进制再转换好了

优化:

#include <iostream>

using namespace std;

int main()
{
    char num[100];
    int str[100] = {0};
    gets(num);
    int term = 1;
    int i = 0;
    int j = 0;
    int flag = 0;
    while(num[i]) i++;
    while(i>0){
        if(flag==3){
            j++;
            flag = 0;
            term = 1;
        }
        str[j] += term*((int)num[--i]-48);
        term *= 2;
        flag++;
    }
    for(int k = j;k>=0;k--)
    cout << str[k];
    return 0;
}

不用搞个什么div啊,只用把 term 重置就好了

6.二进制转十六进制

(二进制转十六进制,四个数字为一组,且要涉及数字和字母的转换)

用整型数组当作中间量,最后把大于9的元素转化为字母后再存到字符数组中

#include <iostream>

using namespace std;

int main()
{
    string num;
    cin>>num;
    int n = num.size();
    int* arr = new int[n/4+1]();
    int term = 1;
    int flag = 0;
    int j = 0;
    int div = 1;
    for(int i=0;i<n;i++){
        if(flag==4){
            arr[j] /= div;
            flag = 0;
            j++;
            div *= 16;
        }
        arr[j] += term*((int)num[i]-48);
        flag++;
        term *= 2;
    }
    if(flag!=4){
        arr[j] /= div;
    }
    char* str = new char[j+2];
    for(int i=0;i<=j;i++){
        if(arr[i]<10)
            str[j-i] = (char)(48+arr[i]);
        else
            str[j-i] = (char)(55+arr[i]);
    }
    str[j+1] = '\0';
    cout<<str;
    return 0;
}

值得注意的是:存入字符时要倒着存,从(j - i)开始,然后 j 的位置要取到,最后还要在末尾加上一个‘ \0’ 终止符!!!

优化:

#include <iostream>

using namespace std;

int main()
{
    string num;
    cin>>num;
    int n = num.size();
    int* arr = new int[n/4+1]();
    int term = 1;
    int flag = 0;
    int j = 0;
    for(int i=0;i<n;i++){
        if(flag==4){
            flag = 0;
            j++;
            term = 1;
        }
        arr[j] += term*((int)num[i]-48);
        flag++;
        term *= 2;
    }
    char* str = new char[j+2];
    for(int i=0;i<=j;i++){
        if(arr[i]<10)
            str[j-i] = (char)(48+arr[i]);
        else
            str[j-i] = (char)(55+arr[i]);
    }
    str[j+1] = '\0';
    cout<<str;
    return 0;
}

7.八进制转二进制

(将每一个数字都拆成三个0与1的组合)

#include <iostream>

using namespace std;

int main()
{
    string str;
    cin>>str;
    int n = str.size();
    int j = 0;
    int flag = 0;
    int term = (int)str[j]-48;
    int* arr = new int[n*3];
    for(int i=0;i<n*3;i++){
        if(flag==3){
            term = (int)str[++j]-48;
            flag = 0;
        }
        arr[i+2-flag*2] = term%2;
        term /= 2;
        flag++;
    }
    for(int i=0;i<3*n;i++)
    cout<<arr[i];
    return 0;
}

注意几个细节:

要用term把字符数组的值转换为数字在进行取模和除法运算

arr【i+2-2*flag】中的-2*flag 是为了实现在循环的小区间内的逆向存储

比如 6 ,计算出来顺序是011,而如果直接用arr【i】存储的话,则由于最后输出时是011,而不是正确的顺序110,所以要在小区间内逆向存储

【这里可以发散一下思维:如何实现每三个字符就逆向倒转一次】

然后这里flag要乘以2是为了抵消 i 的增加!!!【好好理解】

8.十六进制转二进制

(也就是将每一个数字或者字母拆成四个0与1的组合,用除法迭代即可)

(然后注意一下第七题里的事项就ok了)

#include <iostream>

using namespace std;

int fun(char ch)
{
    return (ch>='0' && ch<='9')?((int)ch-48) :((int)ch-87);
}

int main()
{
    string str;
    cin>>str;
    int n = str.size();
    int j = 0;
    int flag = 0;
    int term = fun(str[j]);   //这里规定输入的时小写字母
    int* arr = new int[n*4];
    for(int i=0;i<n*4;i++){
        if(flag==4){
            term = fun(str[++j]);
            flag = 0;
        }
        arr[i+3-flag*2] = term%2;
        term /= 2;
        flag++;
    }
    for(int i=0;i<4*n;i++)
    cout<<arr[i];
    return 0;
}

9.十六进制转八进制

(4个一组的变成3个一组:十六转二再转八)

#include <iostream>

using namespace std;

int fun(char ch)
{
    return (ch>='0' && ch<='9')?((int)ch-48) :((int)ch-87);
}

int main()
{
    string str;
    cin>>str;
    int n = str.size();
    int j = 0;
    int flag = 0;
    int term = fun(str[j]);   //这里规定输入的时小写字母
    int* arr = new int[n*4];
    for(int i=0; i<n*4; i++){
        if(flag==4){
            term = fun(str[++j]);
            flag = 0;
        }
        arr[i+3-flag*2] = term%2;
        term /= 2;
        flag++;
    }
    int m = 4*n/3+1;
    int* s = new int[m]();
    int i = 4*n;
    int mid = 1;
    int w = 0;
    flag = 0;
    while(i>0){
    if(flag==3){
            w++;
            flag = 0;
            mid = 1;
        }
        s[w] += mid*arr[--i];
        mid *= 2;
        flag++;
    }
    for(int k = w; k>=0; k--)
        cout << s[k];
    return 0;
}

10.八进制转十六进制

#include <iostream>

using namespace std;

int main()
{
    string str;
    cin>>str;
    int n = str.size();
    int j = 0;
    int flag = 0;
    int term = (int)str[0]-48;   //这里规定输入的时小写字母
    int* arr = new int[n*3];
    for(int i=0; i<n*3; i++){
        if(flag==3){
            term = (int)str[++j]-48;
            flag = 0;
        }
        arr[i+2-flag*2] = term%2;
        term /= 2;
        flag++;
    }
    int m = 3*n/4+1;
    int* s = new int[m]();
    int i = 3*n;
    int mid = 1;
    int w = 0;
    flag = 0;
    while(i>0){
    if(flag==4){
            w++;
            flag = 0;
            mid = 1;
        }
        s[w] += mid*arr[--i];
        mid *= 2;
        flag++;
    }

    for(int k = w; k>=0; k--){
       if(s[k]<10)
        cout << s[k];
    else cout<< (char)(s[k]+55);
    }
    return 0;
}

11.最小的十六进制

问题描述
  请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。
  请将这个数的十进制形式作为答案提交。
答案提交
  这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

#include <iostream>

using namespace std;

int main()
{
    int temp;
    int flag = 0;
    for(int i = 2023;;i++){
        temp = i;
        for(int j = 0;j<3;j++){
            if(temp%16 <= 9){
                flag = 0;
                break;
            }
            temp /= 16;
            flag++;
        }
        if(flag == 3){
            temp = i;
            break;
        }
    }
    cout<<temp;
    return 0;
}
// Answer: 2730

优化:

#include <iostream>

using namespace std;

int main()
{
    int temp;
    int j;
    for(int i = 2023;;i++){
        temp = i;
        for(j = 0;j<3;j++){
            if(temp%16 <= 9){
                break;
            }
            temp /= 16;
        }
        if(j == 3){
            temp = i;
            break;
        }
    }
    cout<<temp;
    return 0;
}
// Answer: 2730

12.二进制的位数

  十进制整数 2 在十进制中是 1 位数,在二进制中对应 10 ,是 2 位数。
  十进制整数 22 在十进制中是 2 位数,在二进制中对应 10110 ,是 5 位数。
  请问十进制整数 2022 在二进制中是几位数?

tips:直接用十进制转二进制的算法,然后加入一个cnt变量计数即可

#include <iostream>

using namespace std;


int main()
{
    int n;
    cin>>n;
    int cnt = 0;
    while(n>0)
    {
        cnt++;
        n /= 2;
    }
    cout<<cnt;
    return 0;
}
// Answer: 11

要在短时间内准备蓝桥杯比赛,以下是一些有效的备赛建议: 1.确保你理解了比赛规则和题型: 在比赛前,务必细读比赛规则,确保你清楚比赛的时间安排、考试环节和具体的考试题型。通常蓝桥杯比赛的测试内容包括编程语言、算法和数据结构等方面,你必须了解这些内容,在此基础上着手准备考试。 2.选择一个最适合你的编程语言: 蓝桥杯比赛提供了多种编程语言,如C、C++和Java等。你需要在这些语言之间选择一个你最熟悉的语言,这样你能更高效的解决问题并取得更好的成绩。如果你没有选择过适合你的编程语言,那么尽早开始练习并熟悉这门语言。 3.刷牙桥杯历年真题: 从历年真题中了解考试的难度和方向,熟悉解题思路和方法。注意查看认证考试的难度等级,如果没有经验,建议先从入门难度的编程题练起,逐渐提升题目难度。 4.参加线上比赛: 参加线上比赛,可以了解实际考试的系统和平台。在平台上分享你的经历可以互相交流,这有助于你了解你正确和错误的答案,以及如何优化你的答案。 5.做练习: 练习是最好的学习方法。为了提高你的编程能力,我们建议实践,实践,实践!解决编程问题需要最小化编程时间,强调代码的优雅性、 Readability、可读性,尽量减少、调试、以及优化代码等。 总之,要想在短时间内备赛蓝桥杯,你应该提前准备,熟悉比赛规则和题型,做足准备,好好学习,不断练习,相信你一定能在比赛中取得好成绩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值