蓝桥杯基础试题整合

蓝桥杯基础试题整合C++

还剩3天,一定一定要回顾之前掌握的最基础的知识!从基础试题整理,每一题都会抽象对应的考点,如果后续题中出现重复的考点将不再累述。(全文都是基于C++编写,希望对你能有所帮助)
【传送门】
第六届蓝桥杯大赛个人赛省赛(软件类) C/C++大学B组
第十届蓝桥杯大赛软件类省赛C/C++大学B组
第十一届蓝桥杯大赛软件类省赛第二场C/C++大学B组
第十二届蓝桥杯大赛模拟赛(第四期)
第七届蓝桥杯大赛个人赛省赛(软件类) C/C++大学B组
蓝桥杯基础试题整合C++

一、数列排序

问题描述
  给定一个长度为n的数列,将这个数列按从小到大的顺序排列。1<=n<=200
输入格式
  第一行为一个整数n。
  第二行包含n个整数,为待排序的数,每个整数的绝对值小于10000。
输出格式
  输出一行,按从小到大的顺序输出排序后的数列。
样例输入
5
8 3 6 4 9
样例输出
3 4 6 8 9

分析:

1.考查简单的输入、输出(cin>>,cout<<)
2.排序函数sort()【重点说明】
3.循环for语句
4.#include <bits/stdc++.h> 几乎万能头文件

试题答案

#include <bits/stdc++.h>//万能头文件
using namespace std;
int main()
{
    int n,a[200];
    cin>>n;//输入n的值
    cin>>a[0];
    for(int i=1;i<n;i++){//for循环函数,输入下标1~n-1的值
        cin>>a[i];
    }
    sort(a,a+n);//排序,该试题模块最后有详细的使用说明
    for(int i=0;i<n;i++){
        cout<<a[i]<<" ";//输出
    }
    return 0;
}

在这里插入图片描述
重点说明sort()函数

1.功能:对数组进行排序
2.参数含义
(1)包含2个参数 sort(arr,arr+n) :arr表示数组,n表示数组中从下标0开始参与排序的个数,默认按照升序排序
(2)包含3个参数 sort(arr,arr+n,cmp):cmp函数可以修改排序规则,它的返回值是一个bool类型,如果我们需要得到此题的降序排序,当然降序还有一种写法greater<数据类型>()
(代码如下)

#include <bits/stdc++.h>
using namespace std;
bool cmp_1(int a,int b){
    return a>b;
}
bool cmp_2(char a,char b){
    return a>b;
}
int main()
{
    int a[5]={1,5,4,6,2};
    char b[6]="afghj";
    char c[6]="adlkj";
    sort(a,a+5,cmp_1);
    sort(b,b+5,cmp_2);
    sort(c,c+5,greater<char>());
    for(int i=0;i<5;i++){
        cout<<a[i];
    }
    cout<<endl;
    for(int i=0;i<5;i++){
        cout<<b[i];
    }
    cout<<endl;
    for(int i=0;i<5;i++){
        cout<<c[i];
    }
    return 0;
}

相关试题: 数列特征(同样涉及到了排序)

问题描述
给出n个数,找出这n个数的最大值,最小值,和。
输入格式
第一行为整数n,表示数的个数。
第二行有n个数,为给定的n个数,每个数的绝对值都小于10000。
输出格式
输出三行,每行一个整数。第一行表示这些数中的最大值,第二行表示这些数中的最小值,第三行表示这些数的和。
样例输入
5
1 3 -2 4 5
样例输出
5
-2
11
数据规模与约定
1 <= n <= 10000。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,sum=0;
    cin>>n;
    int num[n];
    for(int i=0;i<n;i++){
        cin>>num[i];
        sum+=num[i];
    }
    sort(num,num+n);
    cout<<num[n-1]<<endl;
    cout<<num[0]<<endl;
    cout<<sum<<endl;
    return 0;
}

在这里插入图片描述
相关试题:Huffuman树(同样涉及到了排序)

问题描述
  Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
  给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:
  1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
  2. 重复步骤1,直到{pi}中只剩下一个数。
  在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
  本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。
例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
  1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
  2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
  3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
  4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
  5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。
输入格式
  输入的第一行包含一个正整数n(n<=100)。
  接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。
输出格式
  输出用这些数构造Huffman树的总费用。
样例输入
5
5 3 8 2 9
样例输出
59

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n,sum;
    sum=0;
    cin>>n;
    int P[n];
    for(int i=0;i<n;i++){
        cin>>P[i];
    }
    sort(P,P+n);
    while(n>1){
        P[0]=P[0]+P[1];
        P[1]=P[n-1];
        n--;
        sum+=P[0];
        sort(P,P+n);
    }
    cout<<sum<<endl;
    return 0;
}

在这里插入图片描述

二、十进制转十六进制

问题描述
  十六进制数是在程序设计时经常要使用到的一种整数的表示方式。它有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共16个符号,分别表示十进制数的0至15。十六进制的计数方法是满16进1,所以十进制数16在十六进制中是10,而十进制的17在十六进制中是11,以此类推,十进制的30在十六进制中是1E。
  给出一个非负整数,将它表示成十六进制的形式。
输入格式
  输入包含一个非负整数a,表示要转换的数。0<=a<=2147483647
输出格式
  输出这个整数的16进制表示
样例输入
30
样例输出
1E

分析:

1.考查简单标准整数类型常见存储空间大小和取值范围【附表】
2.进制转化【重点说明】
在这里插入图片描述

试题答案

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    int a;
    cin>>a;
    cout<<setiosflags(ios::uppercase)<<hex<<a<<endl;
    return 0;
}

在这里插入图片描述
重点说明进制转化(利用输入输出流)

1.利用输入输出进行转化,cin<<、cout>>、printf 默认是十进制式,
2.oct为八进制,hex为十六进制,dec为十进制。
3.cout<<是否有大写需求如果有的话(setiosflags(ios::uppercase))<<某种进制<<要转化的数
在这里插入图片描述
是不是很简单,但是这种做法有一个很致命的问题,因为要首先转化成10进制的整形,可是整形的长度是有规定的,即使是长整形对待16进制的转化还是不足够的!但是对于较简单的转换,或是10进制转化还是可以尝试一下的。

相关试题: 十六进制转十进制

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    long long int a;
    cin>>s;
    stringstream ss;;
    ss<<hex<<s;
    ss>>a;//转成10进制
    cout<<a<<endl;
    return 0;
}

在这里插入图片描述

重点说明进制转化(常规做法)

以下是进制转化的常规做法的相关试题:十六进制转八进制
首先将十六转化成二进制,用整形数组存放,再将它转化成八进制[注意前导0的处理]
补充知识点:memset(数组名,赋值,sizeof(数组名)); 就可以改变数组的默认值了

#include<bits/stdc++.h>
using namespace std;
char s1[1000000+10];//字符型数组存放十六进制
int  s2[5000000+10],s3[5000000+10];//整形数组存放二进制和八进制
int main(){
	int n,j,i;
	cin>>n;
	getchar();
	while (n--)
	{
		memset(s1,'\0',sizeof(s1));
		memset(s2,0,sizeof(s2));
		memset(s3,0,sizeof(s3));
		gets(s1);
		int len = strlen(s1);
		j=0;
		for (i=len-1;i>=0;i--)
		{
			int temp;
			if (s1[i]>='A'&&s1[i]<='F')//用字母表示(10~16)需要转化
			temp = s1[i]-'A'+10;//用一个临时变量存储转化的值
			else
			temp = s1[i]-'0';
			int count=4;
			while (count--)
			{
				s2[j++] = temp%2;//用除留余数法转化成二进制
				temp/=2;
			}
		}
		int index=0;
		for (i=0;i<j;i+=3)//将二进制转化成八进制,取三合一法
		{
			int ans = s2[i]*1+s2[i+1]*2+s2[i+2]*4;
			s3[index++] = ans;
		}
		if (s3[index-1]!=0 || index==1)//如果得到的8进制答案仅仅只有一位,而且还是0,那么就不能去掉这个所谓的前导零
		cout<<s3[index-1];

		for (i=index-2;i>=0;i--)
		cout<<s3[i];
		cout<<endl;
	}
	return 0;
}

在这里插入图片描述

三、回文数

问题描述
1221是一个非常特殊的数,它从左边读和从右边读是一样的,编程求所有这样的四位十进制数。
输出格式
按从小到大的顺序输出满足条件的四位十进制数。

分析:

1.回文的含义(a[i]=a[n-i])
2.整数的按位输出【重点说明】

试题答案

#include<bits/stdc++.h>
using namespace std;
int main(){
    int num;
	for(int i=10;i<=99;i++){
        num=i*100+i%10*10+i/10;
        cout<<num<<endl;
	}
	return 0;
}

在这里插入图片描述

重点说明整数的按位输出

1.用整除、取余的方法 num%(所在位+1)/(所在位)
比如123是一个三位数,百位123%1000/100,十位123%100/10,个位123%10/1
在这里插入图片描述
2.这种方法在遇到简单的转换还好,但是遇上一个长整形让你求各个位置上的数字就会显得十分麻烦,这里介绍一种简单的取位方法,转化成字符串型,利用字符数组的下标值来提取数字。
整形转化成字符串型
利用输入流stringsteam
转化成字符串型.str()
在这里插入图片描述

利用方法二再来编写一下这道题

#include<bits/stdc++.h>
using namespace std;
int main(){
    for(int i=10;i<=99;i++){
        stringstream ss;
        ss<<i;
        string result=ss.str();
        cout<<result[0]<<result[1]<<result[1]<<result[0]<<endl;
    }
    return 0;
}

在这里插入图片描述
相关习题

1.特殊回文数
问题描述
  123321是一个非常特殊的数,它从左边读和从右边读是一样的。
  输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n 。
输入格式
  输入一行,包含一个正整数n。
输出格式
  按从小到大的顺序输出满足条件的整数,每个整数占一行。
样例输入
52
样例输出
899998
989989
998899
数据规模和约定
1<=n<=54。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    int num1,num2,num3,num;
    cin>>n;
    for(int i=100;i<=999;i++){
        num1=i/100;
        num2=i%100/10;
        num3=i%10;
        num=num1*2+num2*2+num3;
        if(num==n){
            cout<<i*100+num2*10+num1<<endl;
        }

    }
    if(n%2==0){//只有偶数才有可能是6位数
        for(int i=100;i<=999;i++){
        num1=i/100;
        num2=i%100/10;
        num3=i%10;
        num=num1*2+num2*2+num3*2;
        if(num==n){
            cout<<i*1000+num3*100+num2*10+num1<<endl;
            }
        }
    }
    return 0;
}

在这里插入图片描述

2.特殊的数字
问题描述
  153是一个非常特殊的数,它等于它的每位数字的立方和,即153=111+555+333。编程求所有满足这种条件的三位十进制数。
输出格式
  按从小到大的顺序输出满足条件的三位十进制数,每个数占一行。

分析

1.pow(num,n)这是一个幂函数,括号里的参数,num表示底数,n表示几次幂

#include<bits/stdc++.h>
using namespace std;
int main(){
    int num,num1,num2,num3;
    for(int i=100;i<=999;i++){
        num1=i/100;
        num2=i%100/10;
        num3=i%10;
        num=pow(num1,3)+pow(num2,3)+pow(num3,3);
        if(num==i)
        cout<<i<<endl;
    }
    return 0;
}

在这里插入图片描述

3. 查找整数(虽然不是回文类型的题目,但是和上题一样涉及到了循环和判断,所以就放在一起了)
问题描述
给出一个包含n个整数的数列,问整数a在数列中的第一次出现是第几个。
输入格式
第一行包含一个整数n。
第二行包含n个非负整数,为给定的数列,数列中的每个数都不大于10000。
第三行包含一个整数a,为待查找的数。
输出格式
如果a在数列中出现了,输出它第一次出现的位置(位置从1开始编号),否则输出-1。
样例输入
6
1 9 4 8 3 9
9
样例输出
2
数据规模与约定
1 <= n <= 1000。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,num[1000],f;
    bool flag=false;
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>num[i];
    }
    cin>>f;
    for(int i=0;i<n;i++){
        if(num[i]==f){
            cout<<i+1<<endl;
            flag=true;
            break;
        }
    }
    if(!flag){
        cout<<"-1"<<endl;
    }
    return 0;
}

在这里插入图片描述

4. Fibonacci数列(循环,取模)
问题描述
Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。
当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。
输入格式
输入包含一个整数n。
输出格式
输出一行,包含一个整数,表示Fn除以10007的余数。
样例输入
10
样例输出
55
数据规模与约定
1 <= n <= 1,000,000。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;
    cin>>n;
    int f[n];
    for(int i=0;i<n;i++){
        if(i==0||i==1){
            f[i]=1;
        }
        else{
            f[i]=(f[i-2]+f[i-1])%10007;
        }
    }
    cout<<f[n-1]<<endl;
    return 0;
}


在这里插入图片描述

5.阶乘计算(循环,按位处理)
问题描述
  输入一个正整数n,输出n!的值。
  其中n!=123*…*n。
输入格式
  输入包含一个正整数n,n<=1000。
输出格式
  输出n!的准确值。
样例输入
10
样例输出
3628800

#include <bits/stdc++.h>
/*算法描述
  n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法。
    使用一个数组A来表示一个大整数a,
    A[0]表示a的个位,A[1]表示a的十位,依次类推。
  将a乘以一个整数k变为将数组A的每一个元素都乘以k,请注意处理相应的进位。
  首先将a设为1,然后乘2,乘3,当乘到n时,即得到了n!的值。*/
using namespace std;

int main()
{
    int A[10000];
    memset(A,0,sizeof(A));
    int n,maxx,temp,carry;
    //maxx记录最高位,temp是单位得到的值,carry是进位值
    cin>>n;
    A[0]=1;//先给个位赋值为1
    maxx=0;//最高进位是0(个位)
    carry=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=maxx;j++){//每个位子依次相乘
            temp=A[j]*i+carry;
            A[j]=temp%10;
            carry=temp/10;
            }
            while(carry)
            {
                A[++maxx]+=carry%10;
                carry/=10;
            }
        }
    for(int i=maxx;i>=0;i--){
        cout <<A[i];
    }
    return 0;
}

在这里插入图片描述

6.(数组 高精度)
问题描述
  输入两个整数a和b,输出这两个整数的和。a和b都不超过100位。
算法描述
  由于a和b都比较大,所以不能直接使用语言中的标准数据类型来存储。对于这种问题,一般使用数组来处理。定义一个数组A,A[0]用于存储a的个位,A[1]用于存储a的十位,依此类推。同样可以用一个数组B来存储b。计算c = a + b的时候,首先将A[0]与B[0]相加,如果有进位产生,则把进位(即和的十位数)存入r,把和的个位数存入C[0],即C[0]等于(A[0]+B[0])%10。然后计算A[1]与B[1]相加,这时还应将低位进上来的值r也加起来,即C[1]应该是A[1]、B[1]和r三个数的和.如果又有进位产生,则仍可将新的进位存入到r中,和的个位存到C[1]中。依此类推,即可求出C的所有位。最后将C输出即可。
输入格式
  输入包括两行,第一行为一个非负整数a,第二行为一个非负整数b。两个整数都不超过100位,两数的最高位都不是0。
输出格式
  输出一行,表示a + b的值。
样例输入
20100122201001221234567890
2010012220100122
样例输出
20100122203011233454668012

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string num1,num2;
    int num3[105];
    memset(num3,0,sizeof(num3));
    int length1,length2,maxx,sum,k,flag;
    k=0;
    cin>>num1>>num2;
    length1=num1.length();
    length2=num2.length();
    maxx=max(length1,length2);
    if(length1==maxx){
        for(int i=length2;i<maxx;i++){
            num2='0'+num2;
        }
    }
    else{
         for(int i=length1;i<maxx;i++){
            num1='0'+num1;
        }
    }
    for(int i=maxx-1;i>=0;i--){
        int a,b;
        a=num1[i]-'0';
        b=num2[i]-'0';//补齐高位
        sum=a+b+num3[k];
        num3[k]=sum%10;
        if(sum/10){
            num3[k+1]=sum/10;
            flag=k+1;//如果最高位有进位那么就要留一个位置
        else{
            flag=k;
        }
        k++;
    }
    for(int i=flag;i>=0;i--)
    {cout<<num3[i];}
    cout<<endl;
    return 0;
}

在这里插入图片描述

四、杨辉三角形

问题描述
杨辉三角形又称Pascal三角形,它的第i+1行是(a+b)i的展开式的系数。
它的一个重要性质是:三角形中的每个数字等于它两肩上的数字相加。
下面给出了杨辉三角形的前4行:  
1 
1 1  
1 2 1 
1 3 3 1  
给出n,输出它的前n行。
输入格式
输入包含一个数n。
输出格式
输出杨辉三角形的前n行。每一行从这一行的第一个数开始依次输出,中间使用一个空格分隔。请不要在前面输出多余的空格。
样例输入
4
样例输出
1
1 1
1 2 1
1 3 3 1
数据规模与约定
1 <= n <= 34

分析

1.二维数组 a[行][列] 可以把它想象成一个平面矩阵,在每一个由行列确定位置的空间中存放数值
2.考察空间想象力,杨辉三角两肩上的数字相加该如何表达是解题的关键。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n;
	cin>>n;
	int a[n][n+1];//因为在最左边没有可相加的列,所以我们给多加一列。
	memset(a,0,sizeof(a));//求两肩之和相加,所以我们首先要把默认值设为0;
	a[0][1]=1;//设置一个基准值,这里第一行第一个数字就是基准值,后续打印的数字都是依据这个进行的
	cout<<a[0][1]<<endl;
	for(int i=1;i<n;i++){
		for(int j=1;j<=i+1;j++){
			a[i][j]=a[i-1][j-1]+a[i-1][j];//等于左上角和正上方之和相加
			cout<<a[i][j]<<" ";//注意每个数字之间的空格
		} 
		cout<<endl;//打印完每一行要换行
	}
	return 0;
}

在这里插入图片描述

相关试题:字母图形

问题描述
利用字母可以组成一些美丽的图形,下面给出了一个例子:
ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC
这是一个5行7列的图形,请找出这个图形的规律,并输出一个n行m列的图形。
输入格式
输入一行,包含两个整数n和m,分别表示你要输出的图形的行数的列数。
输出格式
输出n行,每个m个字符,为你的图形。
样例输入
5 7
样例输出
ABCDEFG
BABCDEF
CBABCDE
DCBABCD
EDCBABC
数据规模与约定
1 <= n, m <= 26。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n,m;
    char c;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++)
        {
       		c='A'+abs(i-j);//这里的绝对值是求解的关键
        	cout<<c;
        }
        cout<<endl;
    }
    return 0;
}

在这里插入图片描述
相关试题:回形取数(图形找规律)

问题描述
  回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度。一开始位于矩阵左上角,方向向下。
输入格式
  输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列。接下来m行每行n个整数,表示这个矩阵。
输出格式
  输出只有一行,共mn个数,为输入矩阵回形取数得到的结果。数之间用一个空格分隔,行末不要有多余的空格。
样例输入
3 3
1 2 3
4 5 6
7 8 9
样例输出
1 4 7 8 9 6 3 2 5

#include<bits/stdc++.h> 
using namespace std;
 
int main(){
   int m,n;
   cin>>m>>n;
   int a[m][n];
   int i,j;
   for(i=0;i<m;i++){
    for(j=0;j<n;j++){
        cin>>a[i][j];
    }
   }
   int sum=m*n;//计算总共要走的格子数
   i=-1;j=0;
   while(sum){//判断数字是否都已经取完
    //向下走++i;
    while(a[++i][j]!=-1 && i<m){
        cout<<a[i][j]<<" ";
        a[i][j]=-1;
        sum--;
    }
    i--;//因为最后判断的时候i的值+1了,所以在这里要减去
   //向右走++j
    while(a[i][++j]!=-1 && j<n){
        cout<<a[i][j]<<" ";
        a[i][j]=-1;
        sum--;
    }
    j--;
    //向上走--i
    while(a[--i][j]!=-1 && i>=0){
        cout<<a[i][j]<<" ";
        a[i][j]=-1;
        sum--;
    }
    i++;
    //向左走--j
    while(a[i][--j]!=-1 && j>=0){
        cout<<a[i][j]<<" ";
        a[i][j]=-1;
        sum--;
    }
    j++;
   }
    return 0;
}

在这里插入图片描述

五、01字串(递归)

问题描述
对于长度为5位的一个01串,每一位都可能是0或1,一共有32种可能。它们的前几个是:
00000
00001
00010
00011
00100
请按从小到大的顺序输出这32种01串。
输入格式
本试题没有输入。
输出格式
输出32行,按从小到大的顺序每行一个长度为5的01串。
样例输出
00000
00001
00010
00011
<以下部分省略>

分析

这道题有很多做法,二进制啊,循环,但是我觉得这道题是递归算法很好的切入点。
递归【重点讲解】

#include<bits/stdc++.h>
using namespace std;
int choice[5];
int recursion(int n){
    if(n==5){
        for(int i=0;i<5;i++){
        cout<<choice[i];
        }
        cout<<endl;
        return 1;
    }
    choice[n]=0;
    recursion(n+1);
    choice[n]=1;
    recursion(n+1);
}
int main(){
  recursion(0);
  return 0;
}

在这里插入图片描述
重点讲解:递归函数

递归就是函数不断地调用自己,递归模型需要注意三点
1.缩小问题规模,上题中缩小规模,就是单个位子上选1或是选0
2.提出终止条件,上题中,判断完5位(if(i==5))就终止,这就是终止条件
3.给出处理办法,这里就是将5位选择完毕的01数列打印出来了
上题的递归模型如下所示
一个很详细的递归讲解

int recursion(int n){
    if(n==5){//给出终止条件
        for(int i=0;i<5;i++){
        cout<<choice[i];//给出处理办法
        }
        cout<<endl;
        return 1;
    }
    choice[n]=0;//缩小问题规模,变成单个位子的选择0/1
    recursion(n+1);
    choice[n]=1;
    recursion(n+1);
}

六、 2n皇后问题(贪心算法)

问题描述
  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
  输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出
2

分析

1.贪心算法【重点分析】

#include<bits/stdc++.h>
using namespace std;
int P[10][10];
int n,ans;
int posb[10];
int posw[10];

bool checkw(int cur){
    for(int i=0;i<cur;i++){
        if(posw[cur]==posw[i]||abs(cur-i)==abs(posw[cur]-posw[i]))
        return false;
    }
    return true;
}

bool checkb(int cur){
    for(int i=0;i<cur;i++){
        if(posb[cur]==posb[i]||abs(cur-i)==abs(posb[cur]-posb[i]))
        return false;
    }
    return true;
}

void white(int cur){
    if(cur==n){
        ans++;
    }
    for(int i=0;i<n;i++){
        if(posb[cur]==i)
            continue;
        if(P[cur][i]==0)
            continue;
        posw[cur]=i;
        if(checkw(cur)){
            white(cur+1);
        }
    }
}

void black(int cur){
    if(cur==n){
        white(0);
    }
    for(int i=0;i<n;i++){
        if(P[cur][i]==0){
            continue;
        }
        posb[cur]=i;
        if(checkb(cur)){
            black(cur+1);
        }
    }
}


int main(){
    memset(posb,0,sizeof(posb));
    memset(posw,0,sizeof(posw));
    cin>>n;
    ans=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>P[i][j];
        }
    }
    black(0);
    cout<<ans<<endl;
    return 0;
}

在这里插入图片描述

重点讲解贪心算法

使用贪心算法的前提:
1、原问题复杂度过高;
2、求全局最优解的数学模型难以建立;
3、求全局最优解的计算量过大;
使用贪心算法的方法:
1.明确到底最优解
2.明确子问题的最优解
一个很详细的讲解贪心算法讲解

七、 报时助手(时间问题)

问题描述
  给定当前的时间,请用英文的读法将它读出来。
  时间用时h和分m表示,在英文的读法中,读一个时间的方法是:
  如果m为0,则将时读出来,然后加上“o’clock”,如3:00读作“three o’clock”。
  如果m不为0,则将时读出来,然后将分读出来,如5:30读作“five thirty”。
  时和分的读法使用的是英文数字的读法,其中0~20读作:
  0:zero, 1: one, 2:two, 3:three, 4:four, 5:five, 6:six, 7:seven, 8:eight, 9:nine, 10:ten, 11:eleven, 12:twelve, 13:thirteen, 14:fourteen, 15:fifteen, 16:sixteen, 17:seventeen, 18:eighteen, 19:nineteen, 20:twenty。
  30读作thirty,40读作forty,50读作fifty。
  对于大于20小于60的数字,首先读整十的数,然后再加上个位数。如31首先读30再加1的读法,读作“thirty one”。
  按上面的规则21:54读作“twenty one fifty four”,9:07读作“nine seven”,0:15读作“zero fifteen”。
输入格式
  输入包含两个非负整数h和m,表示时间的时和分。非零的数字前没有前导0。h小于24,m小于60。
输出格式
  输出时间时刻的英文。
样例输入
0 15
样例输出
zero fifteen

分析

1.字符串数组存储
2.对不同时间的判断【重点,会结合(年-闰年,月-大小月份,日,星期,时,分)等涉及到时间的,在接下来的题目代码中详细讲解】

#include<bits/stdc++.h>
using namespace std;
int main(){
    int h,m;
    cin>>h>>m;
    //这里涉及到了时间中的报时问题
    string num_1[21]={"zero","one","two","three","four","five","six","seven",
                    "eight","nine","ten","eleven","twelve","thirteen","fourteen",
                    "fifteen","sixteen","seventeen","eighteen","nineteen","twenty"};
    string num_2[4]={"twenty","thirty","forty","fifty"};
    if(m==0){//首先处理整点情况,只需要对时间进行拆分
        if(h<=20)//大于20小于60的数字,首先读整十的数,然后再加上个位数。
            cout<<num_1[h]<<" o'clock";
        else
            cout<<"twenty "<<num_1[h%10]<<" o'clock";
    }
    else{//处理不是整点的情况,需要随时、分都进行拆分
        if(h<=20)
            cout<<num_1[h]<<" ";
        else
            cout<<"twenty "<<num_1[h%10]<<" ";
        if(m<=20)
            cout<<num_1[m]<<" ";
        else
            cout<<num_2[m/10-2]<<" "<<num_1[m%10];
    }
    return 0;
}

在这里插入图片描述
相关试题:闰年判断

问题描述
给定一个年份,判断这一年是不是闰年。当以下情况之一满足时,这一年是闰年:年份是4的倍数而不是100的倍数;年份是400的倍数。其他的年份都不是闰年。
输入格式
输入包含一个整数y,表示当前的年份。
输出格式
输出一行,如果给定的年份是闰年,则输出yes,否则输出no。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int y;
    cin>>y;
    if(y%100==0){//年份是400的倍数
        if(y%400==0)
        cout<<"yes"<<endl;
        else
        cout<<"no"<<endl;
    }
    else{
        if(y%4==0)//年份是4的倍数而不是100的倍数
        cout<<"yes"<<endl;
        else
        cout<<"no"<<endl;
    }
    return 0;
}

在这里插入图片描述
相关试题:时间转换(秒转化时:分:秒)

问题描述
  给定一个以秒为单位的 时间t,要求用“ < H > : < M > : < S >”的格式来表示这个时间。< H >表示时间,< M >表示分钟,而< S >表示秒,它们都是整数且没有前导的“0”。例如,若t=0,则应输出是“0:0:0”;若t=3661,则输出“1:1:1”。
输入格式
  输入只有一行,是一个整数t(0<=t<=86399)。
输出格式
  输出只有一行,是以“ < H >:< M >:< S >”的格式所表示的时间,不包括引号。
样例输入
0
样例输出
0:0:0

#include<bits/stdc++.h>
using namespace std;
int main(){
    int t;
    cin>>t;
    int h,m,s;
    h=t/3600;//注意时间的进制转化就好了
    m=t%3600/60;
    s=t%60;
    cout<<h<<":"<<m<<":"<<s<<endl;
    return 0;
}

在这里插入图片描述

八、一些简单数论

  1. 质数
  2. 最小公约数
  3. 最大公倍数
  4. 全排列

1.质数:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
相关模型:在这里插入图片描述
相关试题:分解质因数
问题描述
  求出区间[a,b]中所有整数的质因数分解。
输入格式
  输入两个整数a,b。
输出格式
  每行输出一个数的分解,形如k=a1a2a3…(a1<=a2<=a3…,k也是从小到大的)(具体可看样例)
样例输入
3 10
样例输出
3=3
4=22
5=5
6=2
3
7=7
8=222
9=33
10=2
5
数据规模和约定
2<=a<=b<=10000

#include <bits/stdc++.h>
using namespace std;
int num[10005];
bool fun(int n){//重点,判断一个数是否属是质数
    for(int i=2;i<n;i++){
        if(n%i==0)//如果能被除1和它本身以外其他因数的自然数整除
            return false;//那么它不是质数
    }
    return true;
}
int main()
{
    memset(num,0,sizeof(num));
    int a,b;
    cin>>a>>b;
    fun(b);
    for(int i=2;i<=b;i++){
        if(fun(i)){
           num[i]=1;
        }
    }
    for(int i=a;i<=b;i++){
        if(num[i]){
            cout<<i<<"="<<i<<endl;
        }
        else{
            cout<<i<<"=";
            int num1=i;
            for(int j=2;j<i;j++){
                if(num[j]&&num1>1){
                    while(num1%j==0){
                    num1/=j;
                    if(num1!=1)
                    cout<<j<<"*";
                    else
                    cout<<j;
                    }
                }
            }
            cout<<endl;
        }
    }
    return 0;
}

在这里插入图片描述

2.最大公约数:能被a整除,也能被b整除的最大整数
相关模型:在这里插入图片描述
在基础试题中没有涉及但是在真题中有较高的出现频率,让我们试着求一求给定两个数字的最大公约数吧

#include <bits/stdc++.h>
using namespace std;

int fun(int a,int b){
   return b==0?a:fun(b,a%b);
}
int main(){
    int a,b;
    cin>>a>>b;
    int num;
    num=fun(a,b);
    cout<<num<<endl;
}

3.最小公倍数:能整除a,整除b的最小整数
相关模型:基于最小公约数的求解
a*b/最小公约数
那么接着上述代码求解最大公倍数吧

#include <bits/stdc++.h>
using namespace std;

int fun(int a,int b){
   return b==0?a:fun(b,a%b);
}
int main(){
    int a,b;
    cin>>a>>b;
    int num;
    num=fun(a,b);//求出最大公约数
    int num2;
    num2=a*b/num;//求出最小公倍数
    cout<<num<<endl;
}

4.全排列:从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。也就是让你求n!
在很多求一共有几种()的时候会经常用到
涉及到的函数 next_permutation(a,a+3)
其中的参数是(数组名,要全排列的个数)

#include <bits/stdc++.h>
using namespace std;
int main(){
    int a[3]={1,2,3};
    do{
        cout<<a[0]<<a[1]<<a[2]<<endl;
    }while(next_permutation(a,a+3));
    return 0;
}
  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值