1. 程式人生 > >第七屆藍橋杯大賽個人賽省賽C語言A組題目答案

第七屆藍橋杯大賽個人賽省賽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】中,粉紅色所示部分就是合格的剪取。
    
    請你計算,一共有多少種不同的剪取方法。
    
  • 程式碼

    #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
    
  • 思路:這道題其實是找出所有相鄰數的最大公約數的最大公約數,首先對資料進行排序,然後去除重複的數字,最後求出相鄰資料被的最大公約數除過之後的數。原文的連結中的做法無法對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;
    }