2016-第七屆藍橋杯大賽個人賽省賽(軟件類)真題 C大學A組


返回目錄

題目一覽:

1.網友年齡

2.生日蠟燭

3.方格填數

4.快速排序

5.消除尾一

6.寒假作業

7.剪郵票

8.四平方和

9.密碼脫落

10.最大比例

 

1.網友年齡

某君新認識一網友。
當問及年齡時,他的網友說:
“我的年齡是個2位數,我比兒子大27歲,
如果把我的年齡的兩位數字交換位置,剛好就是我兒子的年齡”

請你計算:網友的年齡一共有多少種可能情況?

提示:30歲就是其中一種可能哦.

請填寫表示可能情況的種數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。

思路:枚舉判斷

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 bool check(int x) {
 5     int y = x - 27;
 6     int xx = x%10 * 10 + x/10;
 7     if(xx == y) return true;
 8     return false;
 9 }
10 
11 int main() {
12     int cnt = 0;
13     for(int i=10; i<=99; ++i)
14         if(check(i)) {
15             printf("%d\n", i); 
16             cnt ++;
17         }
18     cout << cnt << endl;
19     return 0;
20 }
1.網友年齡

答案:7

 

2.生日蠟燭

某君從某年開始每年都舉辦一次生日party,並且每次都要吹熄與年齡相同根數的蠟燭。

現在算起來,他一共吹熄了236根蠟燭。

請問,他從多少歲開始過生日party的?

請填寫他開始過生日party的年齡數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。

思路:枚舉+判斷

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 bool flag = true;
 5 int age = 0;
 6 
 7 bool check(int x) {
 8     int sum = 0;
 9     while(sum < 236) { // 這里是< 
10         sum += x;
11         x++;
12     }
13     if(sum == 236) return true;
14     else return false;
15 }
16 
17 int main() {
18     while(flag && age<100) {
19         age++;
20         if(check(age))
21             flag = false;
22     } 
23     cout << age << endl;
24     return 0;
25 }
2.生日蠟燭

答案:26

 

3.方格填數

如下的10個格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+

(如果顯示有問題,也可以參看【圖1.jpg】)

填入0~9的數字。要求:連續的兩個數字不能相鄰。
(左右、上下、對角都算相鄰)

一共有多少種可能的填數方案?

請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。

方法一:將該10個格子按順序拉成一個一維數組,然后將十個數字填進去(全排列),填完之后進行判斷即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int a[11], Ans;
 5 
 6 int calc(int x, int y) {
 7     return abs(a[x]-a[y]);
 8 }
 9 
10 bool check() {
11     if(calc(0, 1) == 1) return false;
12     if(calc(0, 3) == 1) return false;
13     if(calc(0, 4) == 1) return false;
14     if(calc(0, 5) == 1) return false;
15     
16     if(calc(1, 2) == 1) return false;
17     if(calc(1, 4) == 1) return false;
18     if(calc(1, 5) == 1) return false;
19     if(calc(1, 6) == 1) return false;
20 
21     if(calc(2, 5) == 1) return false;
22     if(calc(2, 6) == 1) return false;
23     
24     if(calc(3, 4) == 1) return false;
25     if(calc(3, 7) == 1) return false;
26     if(calc(3, 8) == 1) return false;
27     
28     if(calc(4, 5) == 1) return false;
29     if(calc(4, 7) == 1) return false;
30     if(calc(4, 8) == 1) return false;
31     if(calc(4, 9) == 1) return false;
32     
33     if(calc(5, 6) == 1) return false;
34     if(calc(5, 8) == 1) return false;
35     if(calc(5, 9) == 1) return false;
36     
37     if(calc(6, 9) == 1) return false;
38     if(calc(7, 8) == 1) return false;
39     if(calc(8, 9) == 1) return false;
40     return true;
41 }
42 
43 void dfs(int pos) {
44     if(pos == 10) {
45         if(check()) Ans ++;
46         return ;
47     }
48     for(int i=pos; i<10; ++i) {
49         int t = a[pos]; a[pos] = a[i]; a[i] = t;
50         dfs(pos+1);
51         t = a[pos]; a[pos] = a[i]; a[i] = t;
52     }
53 }
54 
55 int main() {
56     for(int i=0; i<=10; ++i)
57         a[i] = i;
58     dfs(0);
59     printf("%d\n", Ans);
60     return 0;
61 }
3.方格填數-方法一

方法二:在原圖的基礎上加一圈,然后判斷。這個方法的check函數較為簡潔。初始化可以不是-10,只要不與0-9相差±1即可。如圖:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int Map[5][6], Ans;
 5 bool vis[10];
 6 
 7 bool check(int x, int y) {
 8     for(int i=x-1; i<=x+1; ++i) {
 9         for(int j=y-1; j<=y+1; ++j) {
10             if(abs(Map[x][y]-Map[i][j]) == 1) 
11                 return false;  
12         }
13     }
14     return true;
15 }
16 
17 void dfs(int x, int y) {
18     if(x==3 && y==4) { // 最后一個格子也填了 
19         Ans++;
20         return ;
21     }
22     for(int i=0; i<10; ++i) {
23         if(vis[i]) continue; //這個數字用了
24         Map[x][y] = i; // 先放着 
25         if(!check(x, y)) {
26             Map[x][y] = -10; // 
27             continue; //放下不符規則
28         }
29         vis[i] = true;
30         if(y == 4) 
31             dfs(x+1, 1); // 換行 
32         else dfs(x, y+1); // 右邊的格子
33         Map[x][y] = -10; // 回溯 
34         vis[i] = false; 
35     }
36 }
37 
38 int main() {
39     for(int i=0; i<10; ++i) vis[i] = false;
40     for(int i=0; i<5; ++i) // 外面加一圈 
41         for(int j=0; j<6; ++j)
42             Map[i][j] = -10;
43     dfs(1, 2); //第一個填數的格子是(1,2) 
44     printf("%d\n", Ans);
45     return 0;
46 }
3.方格填數-方法二

答案:1580

 

4.快速排序

排序在各種場合經常被用到。
快速排序是十分常用的高效率的算法。

其思想是:先選一個“標尺”,
用它把整個隊列過一遍篩子,
以保證:其左邊的元素都不大於它,其右邊的元素都不小於它。

這樣,排序問題就被分割為兩個子區間。
再分別對子區間排序就可以了。

下面的代碼是一種實現,請分析並填寫划線部分缺少的代碼。

 1 #include <stdio.h>
 2 
 3 void swap(int a[], int i, int j)
 4 {
 5     int t = a[i];
 6     a[i] = a[j];
 7     a[j] = t;
 8 }
 9 
10 int partition(int a[], int p, int r)
11 {
12     int i = p;
13     int j = r + 1;
14     int x = a[p];
15     while(1){
16         while(i<r && a[++i]<x);
17         while(a[--j]>x);
18         if(i>=j) break;
19         swap(a,i,j);
20     }
21     ______________________; // 填空
22     return j;
23 }
24 
25 void quicksort(int a[], int p, int r)
26 {
27     if(p<r){
28         int q = partition(a,p,r);
29         quicksort(a,p,q-1);
30         quicksort(a,q+1,r);
31     }
32 }
33     
34 int main()
35 {
36     int i;
37     int a[] = {5,13,6,24,2,8,19,27,6,12,1,17};
38     int N = 12;
39     
40     quicksort(a, 0, N-1);
41     
42     for(i=0; i<N; i++) printf("%d ", a[i]);
43     printf("\n");
44     
45     return 0;
46 }
4.快速排序

注意:只填寫缺少的內容,不要書寫任何題面已有代碼或說明性文字。

思路:我們發現在partition函數中,是以a[p]為標尺,在[p, r]中比a[p]大的和比a[p]小的做交換,那么完成之后就是:a[p],小,小,大,大,大。a[p]顯然是要與一個數交換的,那么是i,還是j呢(可以輸入i,j輸出看一下)。因為我們這個partition函數是要求吧所有小於a[p]的數字放到左邊,大於的放到右邊,而下標i所指的數是大於a[p]的,與其交換就無法滿足要求,所以是與j交換。

答案:

swap(a, p, j);

 

5.消除尾一

下面的代碼把一個整數的二進制表示的最右邊的連續的1全部變成0
如果最后一位是0,則原數字保持不變。

如果采用代碼中的測試數據,應該輸出:

00000000000000000000000001100111 00000000000000000000000001100000
00000000000000000000000000001100 00000000000000000000000000001100

請仔細閱讀程序,填寫划線部分缺少的代碼。

 1 #include <stdio.h>
 2 
 3 void f(int x)
 4 {
 5     int i;
 6     for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
 7     printf("   ");
 8     
 9     x = _______________________; // 填空
10     
11     for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
12     printf("\n");    
13 }
14 
15 int main()
16 {
17     f(103);
18     f(12);
19     return 0;
20 }
5.消除尾一

注意:只填寫缺少的內容,不要書寫任何題面已有代碼或說明性文字。

思路:很顯然兩個輸出是一樣的,改變的關鍵就是我們填空的地方。那就用到了位運算'&'-按位與:如果兩個相應的二進制位都為1,則該位的結果值為1,否則為0。看下圖

 答案:

x&(x+1)

 

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

就算兩種解法。(加法,乘法交換律后算不同的方案)

你一共找到了多少種方案?


請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。

思路:其實也是全排列問題,把12個格子看成一維數組,然后填充,最后判斷。值得注意的是13!很大,直接跑大約需要一分鍾左右,這是填空題所以沒什么事。但是我們可以添加幾個優化。第22行加的語言可以排除很多無用的排列,大大的提高了效率。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int a[13] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
 5 int Ans;
 6 
 7 bool check() {
 8     if(a[9]%a[10] != 0) return false; // 不能整除 
 9     if(a[0]+a[1] != a[2]) return false; // + - * /
10     if(a[3]-a[4] != a[5]) return false;
11     if(a[6]*a[7] != a[8]) return false;
12     if(a[9]/a[10] != a[11]) return false;
13     return true;
14 }
15 
16 void dfs(int x) {
17     if(x == 13) { // 填完了 
18         if(check()) Ans++;
19     }
20     for(int i=x; i<13; ++i) { 
21         swap(a[x], a[i]);
22         // 剪枝 不滿足加法或減法 的跳過
23         // 因為加減法所需數字在前面 這樣就減少了許多無用的 計算 
24         if((x==2&&a[0]+a[1]!=a[2]) || (x==5&&a[3]-a[4]!=a[5])) {
25             swap(a[x], a[i]);
26             continue;
27         }
28         dfs(x+1);
29         swap(a[x], a[i]);
30     }
31 }
32 
33 int main() {
34     dfs(0);
35     cout << Ans << endl;
36     return 0;
37 }
6.寒假作業

答案:64

 

7.剪郵票

如【圖1.jpg】, 有12張連在一起的12生肖的郵票。
現在你要從中剪下5張來,要求必須是連着的。
(僅僅連接一個角不算相連)
比如,【圖2.jpg】,【圖3.jpg】中,粉紅色所示部分就是合格的剪取。

圖1圖2

請你計算,一共有多少種不同的剪取方法。

請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多余的內容或說明性文字。

思路:直接搜索是不大可能的,我們可以把它轉變成全排列問題。因為一共12張,需要5張,我們可以創建一個數組,存放5個1和7個0,然后對其進行全排列(這里值得注意的是普通的全排列對重復的數字會產生重復的全排列,簡單起見,我們使用c++里面STL中的next_permutation()),然后將其轉化成二維數組,然后用dfs搜索看看有幾個連通塊,只有一個連通塊就是一個可行的方案。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n = 3, m = 4, Map[3][4], Ans;
 5 int a[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1};
 6 int u[4] = {-1, 0, 0, 1},
 7     v[4] = {0, -1, 1, 0};
 8 
 9 void dfs(int x, int y) {
10     Map[x][y] = 0;
11     for(int i=0; i<4; ++i) {
12         int xx = x + u[i];
13         int yy = y + v[i];
14         if(xx>=0 && xx<3 && yy>=0 && yy<4 && Map[xx][yy]==1)
15             dfs(xx, yy);
16     }
17 }
18 
19 bool check() {
20     for(int i=0; i<3; ++i)
21         for(int j=0; j<4; ++j)
22             Map[i][j] = a[4*i+j];
23     int cnt = 0;
24     for(int i=0; i<3; ++i)
25         for(int j=0; j<4; ++j) {
26             if(Map[i][j] == 1) {
27                 dfs(i, j);
28                 cnt++;
29             }
30         }
31     if(cnt == 1) return true;
32     return false;
33 }
34 
35 void work() { // 利用next_permutation生成不重復的排列 
36     do {
37         if(check()) Ans++;
38     }while(next_permutation(a, a+12));
39 }
40 
41 int main() {
42     
43     work();
44     printf("%d\n", Ans);
45     
46     return 0;
47 }
7.剪郵票

答案:116

 

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

資源約定:
峰值內存消耗 < 256M
CPU消耗 < 3000ms

請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

提交時,注意選擇所期望的編譯器類型。

方法一:由題可知a*a<=N/4,b*b<=N/3,c*c<=N/2,d*d<=N,那么我們就可以四層循環來做,但一個很明顯的問題就是會T。然后就是各種神奇的優化,比如說讓a*a<=50,b*b<=500。。。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int N;
 5 
 6 int main() {
 7     cin >> N;
 8     for(int a=0; a*a<=50; a++) {
 9         for(int b=a; b*b<=500; b++) {
10             if(b*b > N) break;
11             for(int c=b; c*c<=N/2; c++) {
12                 if(c*c > N) break;
13                 for(int d=c; d*d<=N; d++) {
14                     if(d*d > N) break;
15                     if(a*a+b*b+c*c+d*d == N) {
16                         printf("%d %d %d %d\n", a, b, c, d);
17                         return 0;
18                     }
19                 }
20             }
21         }
22     }
23     return 0;
24 }
8.四平方和-方法一

方法二:我們可以事先處理c*c+d*d,把結果存起來,用map把結果與c或者d形成映射。然后再枚舉a、b,用N-a*a-b*b來得到c*c+d*d,判斷預處理里面有沒有,有的話在N-a*a-b*b-c*c開方求出d即可。

 1 //#include <bits/stdc++.h>
 2 #include <iostream>
 3 #include <map>
 4 #include <cmath>
 5 using namespace std;
 6 
 7 map<int, int> Map;
 8 int N;
 9 
10 int main() {
11     scanf("%d", &N);
12     for(int c=0; c*c<=N/2; ++c)
13         for(int d=c; c*c+d*d<=N; ++d)
14             if(Map.find(c*c+d*d) == Map.end())
15                 Map[c*c+d*d] = c;
16     for(int a=0; a*a<=N/4; ++a) {
17         for(int b=a; a*a+b*b<=N/2; ++b) {
18             if(Map.find(N-a*a-b*b) != Map.end()) {
19                 int c = Map[N-a*a-b*b];
20                 int d = (int)sqrt(N-a*a-b*b-c*c);
21                 printf("%d %d %d %d\n", a, b, c, d);
22                 return 0;
23             }
24         }
25     }
26     return 0;
27 }
8.四平方和-方法二

 

9.密碼脫落

X星球的考古學家發現了一批古代留下來的密碼。
這些密碼是由A、B、C、D 四種植物的種子串成的序列。
仔細分析發現,這些密碼串當初應該是前后對稱的(也就是我們說的鏡像串)。
由於年代久遠,其中許多種子脫落了,因而可能會失去鏡像的特征。

你的任務是:
給定一個現在看到的密碼串,計算一下從當初的狀態,它要至少脫落多少個種子,才可能會變成現在的樣子。

輸入一行,表示現在看到的密碼串(長度不大於1000)
要求輸出一個正整數,表示至少脫落了多少個種子。

例如,輸入:
ABCBA
則程序應該輸出:
0

再例如,輸入:
ABDCDCBABC
則程序應該輸出:
3

資源約定:
峰值內存消耗 < 256M
CPU消耗 < 1000ms

請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

提交時,注意選擇所期望的編譯器類型。

方法一:爆搜,兩端若不相等就分別往左、右添加,代碼很簡短,但時間復雜度數2^n,是會T的。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 string s;
 5 
 6 int dfs(int l, int r, int cnt) {
 7     if(l >= r) return cnt;
 8     if(s[l] != s[r])
 9         return min(dfs(l+1, r, cnt+1), dfs(l, r-1, cnt+1));
10     else return dfs(l+1, r-1, cnt);
11 }
12 
13 int main() {
14     cin >> s;
15     int Ans = dfs(0, s.length()-1, 0);
16     printf("%d\n", Ans);
17     return 0;
18 }
9.密碼脫落-方法一-超時

方法二:要求是對稱,那我我們把原串翻轉一下,在進行對比可以發現兩串有3個不同的字母,那么我們添加這三個字母不就好了。所以答案就是長度-LCS(最長公共子序列)。

 1 #include <bits/stdc++.h>
 2 #include <string>
 3 using namespace std;
 4 
 5 string s, r_s;
 6 int a[1010][1010];
 7 
 8 int LCS() {
 9     int len = s.length();
10     for(int i=1; i<=len; ++i) {
11         for(int j=1; j<=len; ++j) {
12             if(s[i-1] == r_s[j-1])
13                 a[i][j] = a[i-1][j-1] + 1;
14             else 
15                 a[i][j] = max(a[i-1][j], a[i][j-1]);
16         }
17     }
18     return a[len][len];
19 }
20 
21 int main() {
22     cin >> s;
23     r_s = s;
24     reverse(r_s.begin(), r_s.end());
25     int lcs = LCS();
26     int Ans = s.length() - lcs;
27     printf("%d\n", Ans);
28     return 0;
29 }
9.密碼脫落-方法二

 

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

資源約定:
峰值內存消耗 < 256M
CPU消耗 < 3000ms

請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入...” 的多余內容。

所有代碼放在同一個源文件中,調試通過后,拷貝提交該源碼。

注意: main函數需要返回0
注意: 只使用ANSI C/ANSI C++ 標准,不要調用依賴於編譯環境或操作系統的特殊函數。
注意: 所有依賴的函數必須明確地在源文件中 #include <xxx>, 不能通過工程設置而省略常用頭文件。

提交時,注意選擇所期望的編譯器類型。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM