蓝桥杯2016C语言A组赛题解析

方格填数

如下的10个格子,填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻)一共有多少种可能的填数方案?
这里写图片描述

  • 建二维数组递归填数,每个数字填0-9,但是已经填过的不填
  • 填后一个事判断它的上、左、左上、右上数字是否相邻
  • 填完最后一个数结束
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdlib>
using namespace std;
struct pxy{
    int x;
    int y;  
}; 
const int INF=1e9;
struct pxy s[4]={
    {-1, 0},{0,-1},{-1,-1},{-1,1}
};
int a[5][5];
bool used[10];
int sum;
//当前填入的数字和四个位置填入的数字比较
bool match(int n, int x,int y)
{
    int xx,yy;
    for(int i=0;i<4;i++){
        xx=x+s[i].x;
        yy=y+s[i].y;

        if(xx>=1 && yy>=1 && xx<=3 && yy<=4){
            if(abs(n-a[xx][yy]) == 1) return false;         
        }
    }
    return true;
} 

void f(int x, int y)
{
    if(x==3 && y==4){
        sum++;
        return;
    } 
    for(int i=0;i<10;i++){
        if(!used[i] && match(i,x,y)){
            a[x][y]=i;
            used[i]=true;   
            //依次填注意拐弯
            if(y==4)
                f(x+1,1);
            else
                f(x,y+1);

            used[i]=false;
            a[x][y]=-INF;

        }

    }

} 

 int main()
 {
    for(int i=1;i<=3;i++)
    {
        for(int j=1;j<=4;j++)
        {
            a[i][j]=-INF;
        }
     }
    f(1,2);
    cout<<sum<<endl;
    return 0;
 }

快速排序

排序在各种场合经常被用到。 快速排序是十分常用的高效率的算法。其思想是:先选一个“标尺”, 用它把整个队列过一遍筛子,以保证:其左边的元素都不大于它,其右边的元素都不小于它。这样,排序问题就被分割为两个子区间。 再分别对子区间排序就可以了。下面的代码是一种实现,请分析并填写划线部分缺少的代码。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


void swap(int a[], int i, int j)
{
    int t=a[i];
    a[i]=a[j];
    a[j]=t;
} 
//把数组介于p-r的元素分割成两个部分 
int partition(int a[], int p, int r)
{
    int i=p;
    int j=r+1;
    int x=a[p];

    //以a[p]为基准从两边依次找小于a[p]数和大于a[p]的数交换 
    //大于a[p]的数放左边 
    while(1)
    {
        //从左向右开始找第一小于a[p]的数 
        while(i<r && a[++i]<x);
        //从右向左开始找第一大于a[p]的数 
        //当前这个数大于a[p] 
        while(a[--j]>x);

        if(i>=j)break;      
        swap(a,i,j);
    }
/**********************************/
//使a[p]这个数在交接点,a[p]原本在最左边,左边存大数所以只能和最后一个大数交换 
    swap(a,p,j);
/**********************************/
    return j;
}

void quicksort(int a[], int p, int r)
{
    if(p<r){
        int q = partition(a,p,r);
        quicksort(a,p,q-1);
        quicksort(a,q+1,r);

    }
}

int main()
{
    int i;

    int a[]={
        5,13,6,24,2,8,19,27,6,12,1,17
    };

    int N=12;
    for(i=0;i<N;i++)
    {
        cout<<a[i]<<'\t';
    }
    cout<<endl;


    quicksort(a,0,N-1);

    for(i=0;i<N;i++)
    {
        cout<<a[i]<<'\t';
    }
    cout<<endl;
}

消除尾一

下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0 如果最后一位是0,则原数字保持不变。如果采用代码中的测试数据,应该输出:
00000000000000000000000001100111 00000000000000000000000001100000 00000000000000000000000000001100 00000000000000000000000000001100
请仔细阅读程序,填写划线部分缺少的代码。

  • 连续的1左边那位肯定是0,0111111…,加1后变为10000…..可以‘&与’
  • 最有一位是0,与0还是0
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio> 
using namespace std;

void f(int x)
{
    int i;
    for(i=0;i<32;i++)printf("%d",(x>>(31-i))&1);
    printf(" ");

/********************************************/ 
    x=x&(x+1);
/********************************************/  
    for(i=0;i<32;i++)printf("%d",(x>>(31-i))&1);
    printf("\n");
}

int main()
{
    f(103);
    f(12);
    return 0;
}

寒假作业

这里写图片描述
每个方块代表1~13中的某一个数字,但不能重复。加法,乘法交换律后算不同的方案。你一共找到了多少种方案?请填写表示方案数目的整数。

  1. 递归填数,填到12个数为止
  2. 每个数字可以填1到13,但是填过的不在填
  3. 填完第3、6、9、12个分别判断是否符合要求
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio> 
using namespace std;

int a[12];
int sum;
int used[15];
void f(int dep)
{
    if(dep == 12)
    {
        if(a[9] / a[10] == a[11])
            sum++;
        return;
    }

    if(dep == 9)
    {
        if(a[6] * a[7] != a[8])
            return;
    }

    if(dep == 6)
    {
        if(a[3] - a[4] != a[5])
            return;
    }

    if(dep == 3)
    {
        if(a[0] + a[1] != a[2])
            return;
    }

    for(int i=1;i<=13;i++)
    {
        if(!used[i])
        {
            used[i]=1;
            a[dep]=i;
            f(dep+1);

            used[i]=0;
            a[dep]=-1;
        }
    }

}

int main()
{
    for(int i=0;i<12;i++)
    {
        a[i]=-1;
    }

    f(0);
    cout<<sum<<endl; 
}

剪邮票

这里写图片描述
有12张连在一起的12生肖的邮票。 现在你要从中剪下5张来,要求必须是连着的。 (仅仅连接一个角不算相连)。请你计算,一共有多少种不同的剪取方法。请填写表示方案数目的整数

  1. 取出5张邮票的不同组合
  2. 判断每种组合中,每张邮票是否至少和另一张相连
#include <iostream>
using namespace std;
const int N=12;
const int n=5;
//n: 总共要取几个数
//N:所有数个数 

bool used[N];
int s[6*11*12][n];
int sum;
int result;
//选择的5个数,每个数必须与其中一个数相邻 
int junc(int a[])
{
    int i; 
    int j;
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
        {
            if(i==j) continue;
            if(abs(a[i]-a[j])==1 || abs(a[i]-a[j])==4)
                break;      
        }
        if(j == n)
            return 0;
    }
    if(i == n)
        return 1;
}

//取a[]中n个数不同组合全部存到s[][]中 
//每个数可以选择用或者不用 
//pos:当前递归到a[]中第几个数
//cnt:取了几个数
void c(int pos, int cnt, int a[])
{
    if(cnt == n){
        int m=0;
        for(int i=0;i<N;i++){   
        //取a[]中用到的数存入s[][]  
            if(used[i]){    
                s[sum][m] = a[i];
                m++;
            }           
        }
        sum++;
        return;
    }   
    if(pos == N)return; 
    if(!used[pos]){
        used[pos]=true;
        c(pos+1, cnt+1, a); 
        used[pos]=false;
    }
    c(pos+1, cnt, a);
}

int main()
{
    int a[N];
    for(int i=0;i<N;i++)
        a[i]=i+1;
    c(0,0,a);
    cout<<"组合种数:"<<sum<<endl;
    for(int i=0;i<sum;i++)
        if(junc(s[i]))
            result++;
    cout<<"不同剪法:"<<result<<endl;
} 

四平方和

四平方和定理,又称为拉格朗日定理: 每个正整数都可以表示为至多4个正整数的平方和。 如果把0包括进去,就正好可以表示为4个数的平方和。对于一个给定的正整数,可能存在多种平方和的表示法。 要求你对4个数排序: 0 <= a <= b <= c <= d 并对所有的可能表示法按 a,b,c,d 为联合主键升序排列,最后输出第一个表示法。
程序输入为一个正整数N (N<5000000)
要求输出4个非负整数,按从小到大排序,中间用空格分开
例如,输入: 5
则程序应该输出: 0 0 1 2
再例如,输入: 12
则程序应该输出: 0 2 2 2
再例如,输入: 773535
则程序应该输出: 1 1 267 838

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    int n,s;
    cin>>n;
    s=(int)(sqrt((double)n));
    for(int i=0;i<=s;i++)
    {
        for(int j=0;j<=(int)(sqrt((double)(n-i*i)));j++)
        {
            for(int t=0;t<=(int)(sqrt((double)(n-i*i-j*j)));t++)
            {
                for(int a=0;a<=(int)(sqrt((double)(n-i*i-j*j-t*t)));a++)
                {
                    if((i*i + j*j + t*t + a*a) == n){
                        cout<<i<<' '<<j<<' '<<t<<' '<<a<<endl;
                        return 0;
                    }
                } 
            } 
        } 
    } 
    cout<<"none!"<<endl;
    return 0;
}

密码脱落

X星球的考古学家发现了一批古代留下来的密码。这些密码是由A、B、C、D 四种植物的种子串成的序列。仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串)。 由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征。
你的任务是:
给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子。输入一行,表示现在看到的密码串(长度不大于1000) 要求输出一个正整数,表示至少脱落了多少个种子。
例如,输入: ABCBA
则程序应该输出: 0
再例如,输入: ABDCDCBABC 则程序应该输出: 3

  1. 当两边不一样分别递归左插和右插递归,两边一样向里面递进
  2. 最后取步数最小的
#include <iostream>
#include <string>
using namespace std;
string::size_type amin ;
string s;
void dfs(string::size_type l, string::size_type r, string::size_type k)
{
    if(l >= r)
    {
        if(k < amin)
        {
            amin = k;
        }

        return;
    }   

    if(s[l] == s[r])
        dfs(l+1, r-1, k);
    else{
        dfs(l+1, r, k+1);
        dfs(l, r-1, k+1);
    }
}

int main()
{
    string::size_type len;  
    s="ABDCDCBABC";
    len = s.size();
    amin = len;

    dfs(0, len-1, 0);
    cout<<amin<<endl;
}

最大比例

X星球的某个大奖赛设了M级奖励。每个级别的奖金是一个正整数。 并且,相邻的两个级别间的比例是个固定值。也就是说:所有级别的奖金数构成了一个等比数列。比如: 16,24,36,54 其等比值为:3/2 现在,我们随机调查了一些获奖者的奖金数。 请你据此推算可能的最大的等比值。

输入格式
第一行为数字 N (0<N<100),表示接下的一行包含N个正整数
第二行N个正整数Xi(Xi<1 000 000 000 000),用空格分开。
每个整数表示调查到的某人的奖金数额  
要求输出: 
一个形如A/B的分数,要求A、B互质。表示可能的最大比例系数  
测试数据保证了输入格式正确,并且最大比例是存在的。
例如,输入: 3 
1250 200 32  
程序应该输出: 25/4  
再例如,输入: 4 
3125 32 32 200  
程序应该输出: 5/2 
再例如,输入: 3 
549755813888 524288 2  
程序应该输出: 4/1

 1. 去重排序
 2. 保存相邻两个数的的比例
 3. 寻找第一个比例开几次方后,和其它比例成次幂关系
 4. 转换小数为分数
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int a[100];
int n;

int is_integer(double n)
{
    double a;
    a=floor(n);
    if(n-a < 1e-7)
        return 1;
    else
        return 0;
}
int match(double a, double b)
{
    if(fabs(a-b)<1e-7)
        return 1;
    else
        return 0;
}
double f(double a[], int n)
{
    double min=a[0];
    double temp;
    int i=1;
    int j; 
    do
    {
        temp=pow(min,(double)1/(double)i);

        for(j=0;j<n;j++)
        {
            if(!is_integer( log(a[j])/log(temp) ) )
                break;
        }
        i++;
        if(j==n)
            return temp;


    }while(1);

}
int main()
{
    double result;
    double b[100];
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    cout<<endl; 
    sort(&a[0],&a[n]);

    int i,bn=0;
    for(i=0;i < n-1;i++)
    {
        if(a[i]!=a[i+1])
        {
            b[bn]=(double)(a[i+1]) / (double)(a[i]);
            bn++;
        }

    }

    result=f(b,bn);
    cout<<"result:"<<result<<endl;  
    //寻找p/t等于result的数字p和t 
    for(double t=1;t<100;t++)
    {
        for(double p=t+1;p/t < result+1;p++)
        {
            if(match(result,p/t))
            {
                cout<<p<<"/"<<t<<endl;
                return 0;
            }
        }
    }
} 

猜你喜欢

转载自blog.csdn.net/qq_23084801/article/details/78734447