第七届蓝桥杯大赛个人赛省赛C语言A组题目答案

第七届省赛题目

注意

  • 简单的题目,只是写了一个函数实现功能,对于复杂的题目,会给出全部代码

1

  • 题目

    网友年龄
    
    某君新认识一网友。
    当问及年龄时,他的网友说:
    “我的年龄是个2位数,我比儿子大27岁,
    如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄”
    
    请你计算:网友的年龄一共有多少种可能情况?
    
    提示:30岁就是其中一种可能哦.
    
  • 代码

    void test01()
    {
        int num = 0;
        for(int i=0;i<=9;i++)
        {
            for(int j=0;j<i;j++)
            {
                if( 9*(i-j) == 27 )
                {
                    num++;
                    //printf("%d, %d\n", 10*i+j, 10*j+i);
                }
            }
        }
        printf("num : %d\n", num);
    }
    

2

  • 题目

    生日蜡烛
    
    某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
    
    现在算起来,他一共吹熄了236根蜡烛。
    
    请问,他从多少岁开始过生日party的?
    
  • 注意:这道题不需要进行两层循环即可。

  • 代码

    void test02()
    {
        int sum = 0;
        int si = 0, ei = 0;
        int goal = 236;
        while( sum != goal )
        {
            if( sum < goal )
            {
                ei++;
                sum += ei;
            }
            else if( sum > goal )
            {
                sum -= si;
                si++;
            }
        }
        printf("si : %d, ei : %d\n", si, ei);
    } 
    

3

  • 题目

    方格填数
    
    如下的10个格子
       +--+--+--+
       |  |  |  |
    +--+--+--+--+
    |  |  |  |  |
    +--+--+--+--+
    |  |  |  |
    +--+--+--+
    
    (如果显示有问题,也可以参看【图1.jpg】)
    
    填入0~9的数字。要求:连续的两个数字不能相邻。
    (左右、上下、对角都算相邻)
    
    一共有多少种可能的填数方案?
    
  • 思路:DFS

  • 代码

    #include <stdio.h>
    
    int num[3][4];
    int sum = 0;
    
    bool isFilled[10];
    
    int abs(int n)
    {
        return n >= 0 ? n : -n;
    }
    
    // 在num[r][c]处防止i符合规则则返回true 
    bool isLegal(int r, int c, int val)
    {
        if( r == 0 && c == 0 )
            return true;
        else if( r == 0 )
            return abs(val-num[r][c-1]) > 1;
        else if( c == 0 )
            return abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c+1])>1;
        else if( c != 3 )
            return abs(val-num[r][c-1]) > 1 && abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c-1])>1 && abs(val-num[r-1][c+1])>1;
        else
            return abs(val-num[r][c-1]) > 1 && abs(val-num[r-1][c]) > 1 && abs(val-num[r-1][c-1])>1;
    }
    
    void dfs(int r, int c)
    {
        if( r == 2 && c == 3 )
        {
            sum++;
            return;
        }
    
        for(int i=0;i<=9;i++)
        {
            if( !isFilled[i] && isLegal(r, c, i) )
            {
                num[r][c] = i;
                isFilled[i] = true;
                dfs( r + (c+1)/4, (c+1)%4 );
                isFilled[i] = false;
            }
        }
    
    }
    
    int main()
    {
        num[0][0] = -10;
        num[2][3] = -10;
        for(int i=0;i<10;i++)
            isFilled[i] = false;
        dfs( 0, 1 );
        printf("%d\n", sum);
        return 0;
    }
    

4

  • 题目

    快排的填空实现
    
  • 代码

    #include <stdio.h>
    
    void swap(int a[], int i, int j)
    {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    
    int partition(int a[], int p, int r)
    {
        int i = p;
        int j = r + 1;
        int x = a[p];
        while(1){
            while(i<r && a[++i]<x);
            while(a[--j]>x);
            if(i>=j) break;
            swap(a,i,j);
        }
        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;
    
        quicksort(a, 0, N-1);
    
        for(i=0; i<N; i++) printf("%d ", a[i]);
        printf("\n");
    
        return 0;
    }
    

5

  • 题目

    消除尾一
    
    下面的代码把一个整数的二进制表示的最右边的连续的1全部变成0
    如果最后一位是0,则原数字保持不变。
    
    如果采用代码中的测试数据,应该输出:
    00000000000000000000000001100111   00000000000000000000000001100000
    00000000000000000000000000001100   00000000000000000000000000001100
    
  • 代码

    #include <stdio.h>
    
    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;
    }
    

6

  • 题目

    寒假作业
    
    现在小学的数学题目也不是那么好玩的。
    看看这个寒假作业:
    
       □ + □ = □
       □ - □ = □
       □ × □ = □
       □ ÷ □ = □
    
       (如果显示不出来,可以参见【图1.jpg】)
    
    每个方块代表1~13中的某一个数字,但不能重复。
    比如:
     6  + 7 = 13
     9  - 8 = 1
     3  * 4 = 12
     10 / 2 = 5
    
    以及: 
     7  + 6 = 13
     9  - 8 = 1
     3  * 4 = 12
     10 / 2 = 5
    
    就算两种解法。(加法,乘法交换律后算不同的方案)
    
    你一共找到了多少种方案?
    
  • 代码

    #include <stdio.h>
    bool isUsed[14];
    int num[4][3];
    int sum = 0;
    
    // 判断第几行最后一个值填入这个是否正确 
    bool right( int r, int val )
    {
        switch(r)
        {
            case 0:
                return num[r][0] + num[r][1] == val;
                break;
            case 1:
                return num[r][0] - num[r][1] == val;
                break;
            case 2:
                return num[r][0] * num[r][1] == val;
                break;
            case 3:
                return val * num[r][1] == num[r][0];
                break;
            default:
                return false;
        }
    }
    
    void dfs( int r, int c )
    {
        if( r == 4 )
        {
            sum++;
            if( sum <= 3 )
            {
                for(int i=0;i<4;i++)
                {
                    for(int j=0;j<3;j++)
                        printf("%4d", num[i][j]);
                    printf("\n");
                }
            }
            printf("\n");
            return;
        }
    
        for(int i=1;i<=13;i++)
        {
            // 该数没有被使用 
            if( !isUsed[i] )
            {
                isUsed[i] = true;
                // 是计算的结果,则需要判断一下 
                if( c != 2 || right(r, i) )
                {
                    num[r][c] = i;
                    dfs( r+(c+1)/3, (c+1)%3 );
                }
    
                isUsed[i] = false;
            }
        }
    }
    
    int main()
    {
        for(int i=1;i<14;i++)
            isUsed[i] = false;
        dfs( 0, 0 );
        printf("%d\n", sum);
    }
    

7

  • 题目

    剪邮票
    
    如【图1.jpg】, 有12张连在一起的12生肖的邮票。
    现在你要从中剪下5张来,要求必须是连着的。
    (仅仅连接一个角不算相连)
    比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。
    
    请你计算,一共有多少种不同的剪取方法。
    
  • 注:有人用dfs求解,我没怎么看懂23333,参考链接在这:http://blog.csdn.net/kavu1/article/details/51130029

  • 代码

    #include <stdio.h>
    
    bool map[3][4];
    int sum = 0;
    
    int idx[5];
    
    int abs( int a )
    {
        return a >= 0 ? a : -a;
    }
    
    bool connect(int a, int b)
    {
        int r1 = a/4, c1 = a%4;
        int r2 = b/4, c2 = b%4;
        return abs(r1-r2)+abs(c1-c2) == 1;
    }
    
    bool match()
    {
        bool ret = false;
        for(int i=0;i<5;i++)
        {
            ret = false;
            for(int j=0;j<5;j++)
            {
                if( connect(idx[i],idx[j]) )
                {
                    ret = true;
                    break;
                }
            }
            if( !ret ) // 如果无法连接,则退出并返回 
                break;
        }
        return ret;
    
    }
    
    int main()
    {
    
        // 随机选取5个点,看是否能够 
        for(int i1=0;i1<12;i1++)
        {
            idx[0] = i1;
            for(int i2=i1+1;i2<12;i2++)
            {
                idx[1] = i2;
                for( int i3=i2+1;i3<12;i3++ )
                {
                    idx[2] = i3;
                    for(int i4=i3+1;i4<12;i4++)
                    {
                        idx[3] = i4;
                        for(int i5=i4+1;i5<12;i5++)
                        {
                            idx[4] = i5;
                            if( match() )
                            {
                                sum++;
                            }
                        }
                    }
                }
            }
        }
        printf("ans : %d\n", sum);
        return 0;
    }
    

8

  • 题目

    四平方和
    
    四平方和定理,又称为拉格朗日定理:
    每个正整数都可以表示为至多4个正整数的平方和。
    如果把0包括进去,就正好可以表示为4个数的平方和。
    
    比如:
    5 = 0^2 + 0^2 + 1^2 + 2^2
    7 = 1^2 + 1^2 + 1^2 + 2^2
    (^符号表示乘方的意思)
    
    对于一个给定的正整数,可能存在多种平方和的表示法。
    要求你对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 <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    int num[5];
    int goal = 0;
    
    int number = 0;
    
    void dfs(int n, int sum)
    {
        if( number != 0 )
            exit(0);
        if(  sum > goal || n > 5 )
            return;
        if( n == 5 )
        {
            if( sum == goal )
            {
                number++;
                for( int i=1;i<5;i++ )
                    printf("%d ", num[i]);
                printf("\n");
            }
            return;
        }
        // 这是不等于5的情况 
        if( sum == goal )
            return;
    
        num[n] = num[n-1];
        int tmp = sum;
        while( tmp < goal )
        while( tmp < goal )
        {
            tmp = sum+num[n]*num[n];
            dfs( n+1, tmp );
            num[n]++;
        }
    }
    
    int main()
    {
        scanf("%d", &goal);
        dfs(1, 0);
    
        return 0;
    }
    

9

  • 题目

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

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <string.h>
    
    char s[1020];
    int min_len = 9999;
    int s_len = 0;
    
    void dfs(int l, int r, int len)
    {
        if( l>=r )
        {
            if( min_len > len )
                min_len = len;
            return;
        }
        // 对称则继续检测 
        if( s[l] == s[r] )
            dfs( l+1, r-1, len );
        // 2种情况 
        else
        {
            dfs(l+1, r, len+1);
            dfs(l, r-1, len+1);
        }
    
    }
    
    
    int main()
    {
        gets( s );
        s_len = strlen( s );
    
        dfs( 0, s_len-1, 0 );
        printf("min len : %d\n", min_len);
        return 0;
    }
    

10

  • 题目

    最大比例
    
    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
    
  • 参考链接:http://www.aichengxu.com/cyvyan/6607933.htm
  • 思路:这道题其实是找出所有相邻数的最大公约数的最大公约数,首先对数据进行排序,然后去除重复的数字,最后求出相邻数据被的最大公约数除过之后的数。原文的链接中的做法无法对16,24,81的测试数据正确求解(我认为正确的解为3/2,原文链接代码得到的是9/4
  • 注意:long long的数据输入与输出需要使用%lld,否则在输出时,会影响后面数据的输出,在输入时,对于很大的数据,无法读取。
  • 代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <string.h>
    
    int N;
    long long bonus[100];
    long long res[100], p1[100], p2[100];
    long long num1, num2;
    
    void sort()
    {
        long long tmp;
        for(int i=0;i<N;i++)
        {
            for(int j=i+1;j<N;j++)
            {
                if( bonus[j] < bonus[i] )
                {
                    tmp = bonus[j];
                    bonus[j] = bonus[i];
                    bonus[i] = tmp;
                }
            }
        }
    }
    
    void removeSame()
    {
        int k = 1;
        res[0] = bonus[0];
        for(int i=1;i<N;i++)
        {
            if( bonus[i] == bonus[i-1] )
                continue;
            res[k++] = bonus[i];
        }
        N = k;
    
    }
    
    long long gcd(long long a, long long b)
    {
        long long t;
        if( b == 0 )
            return a;
        else
            return gcd( b, a%b );
    }
    
    long long max(long long a, long long b)
    {
        return a >= b ? a : b;
    }
    
    long long min(long long a, long long b)
    {
        return a <= b ? a : b;
    }
    
    void solve()
    {
        int tmp;
        int k;
        if( N == 1 )
        {
            num1 = 1;
            num2 = 1;
            return;
        }
        else if( N == 2 )
        {
            tmp = gcd( res[1], res[0] );
            num1 = res[1] / tmp;
            num2 = res[0] / tmp;
            return;
        }
        else
        {
            k = 0;
            long long g,g1,g2;
            for(int i=1;i<N;i++)
            {
                tmp = gcd( res[i], res[i-1] );
                p1[k] = res[i] / tmp;
                p2[k] = res[i-1] / tmp;
                k++;
            }
        }
        double t = 999999; // 存储最小的公约数 
        long long  t1, t2, tt1, tt2, max_tmp, min_tmp;
        long long max_p1, max_p2, min_p1, min_p2;
        for(int i=0;i<N-1;i++)
        {
            for(int j=i+1;j<N-1;j++)
            {
                if( p1[i]*p2[j] == p1[j]*p2[i] )
                {
                    t1 = p1[i];
                    t2 = p2[i];
                }
                else
                {
                    max_p1 = max( p1[i], p1[j] );
                    max_p2 = max( p2[i], p2[j] );
    
                    min_p1 = min( p1[i], p1[j] );
                    min_p2 = min( p2[i], p2[j] );
    
                    max_tmp = max_p1;
                    min_tmp = min_p1;
                    max_p1 = max( min_tmp, max_tmp/min_tmp );
                    min_p1 = min( min_tmp, max_tmp/min_tmp );
    
                    max_tmp = max_p2;
                    min_tmp = min_p2;
                    max_p2 = max( min_tmp, max_tmp/min_tmp );
                    min_p2 = min( min_tmp, max_tmp/min_tmp );
    
                    t1 = gcd( max_p1, min_p1 );
                    t2 = gcd( max_p2, min_p2 );
    
                }
    
                // 在之前的程序中可知p1>p2 
                if( 1.0*t1/t2 < t )
                {
                    t = 1.0*t1/t2;
                    tt1 = t1;
                    tt2 = t2;
                }
            }
        }
        tmp = gcd(tt1, tt2);
        num1 = tt1 / tmp;
        num2 = tt2 / tmp;
    }
    
    
    int main()
    {
        scanf("%d", &N);
        for(int i=0;i<N;i++)
            scanf("%lld", &bonus[i]);
        sort();
        removeSame();
    
        solve();
    
        printf("%lld/%lld\n", num1, num2);
        return 0;
    }
    
  • 14
    点赞
  • 77
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

littletomatodonkey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值