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


返回目錄

題目一覽:

1.報紙頁數

2.煤球數目

3.平方怪圈

4.打印方塊

5.快速排序

6.湊算式

7.寒假作業

8.冰雹數

9.卡片換位

10.密碼脫落

 

1.報紙頁數

X星球日報和我們地球的城市早報是一樣的,
都是一些單獨的紙張疊在一起而已。每張紙印有4版。

比如,某張報紙包含的4頁是:5,6,11,12,
可以確定它應該是最上邊的第2張報紙。

我們在太空中撿到了一張X星球的報紙,4個頁碼分別是:
1125,1126,1727,1728

請你計算這份報紙一共多少頁(也就是最大頁碼,並不是用了幾張紙哦)?

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

思路:首先要知道報紙的頁碼是怎么編號的。如下圖。

  方案一:已知最小頁碼的5減去1是4,而最大頁碼16減去已知最大頁面12也是4,這就很巧妙了,設最大頁碼是x,則有:x-已知最大頁碼==已知最小頁碼-1。

  方案二:可以發現每一張的每一面的兩個數字相加都是一樣的,如下圖:16+1 == 15+2 == 14+3 == ... == 9+8,且都比最大頁碼大1,設最大頁碼為x,則有:x+1 == 已知最大+已知最小 == 已知較大+已知較小。

 

答案:2852

 

2.煤球數目

有一堆煤球,堆成三角棱錐形。具體:
第一層放1個,
第二層3個(排列成三角形),
第三層6個(排列成三角形),
第四層10個(排列成三角形),
....
如果一共有100層,共有多少個煤球?

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

思路:枚舉

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int main() {
 5     int cnt = 0;
 6     int Ans = 0;
 7     for(int i=1; i<=100; ++i) {
 8         cnt += i;
 9         Ans += cnt;
10     } 
11     printf("%d\n", Ans);
12     return 0;
13 }
2.煤球數目

答案:171700

 

3.平方怪圈

如果把一個正整數的每一位都平方后再求和,得到一個新的正整數。
對新產生的正整數再做同樣的處理。

如此一來,你會發現,不管開始取的是什么數字,
最終如果不是落入1,就是落入同一個循環圈。

請寫出這個循環圈中最大的那個數字。

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

思路:枚舉若干個數字,然后按照要求做個幾十遍,期間把最大值保存,然后輸出。這若干個數一比對就出來了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 void work(int x) {
 5     int Max = -1;
 6     printf("%d: ", x);
 7     for(int i=1; i<=20; ++i){
 8         int t = 0;
 9         int xx = x;
10         while(x) {
11             int v = x%10;
12             t = t + v * v;
13             x /= 10;
14         }
15         x = t;
16         printf("%d ", x);
17         Max = max(x, Max);
18     }
19     printf("Max = %d\n", Max);
20     return ;
21 }
22 
23 int main() {
24     for(int i=1; i<=20; ++i)
25         work(i);
26     return 0;
27 }
3.平方怪圈

答案:145

 

4.打印方塊

小明想在控制台上輸出 m x n 個方格。
比如 10x4的,輸出的樣子是:
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+

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

以下是小明寫的程序,請你分析其流程,填寫划線部分缺少的代碼。

 1 #include <stdio.h>
 2 
 3 //打印m列,n行的方格 
 4 void f(int m, int n)
 5 {
 6     int row;
 7     int col;
 8     
 9     for(row=0; row<n; row++){
10         for(col=0; col<m; col++) printf("+---");
11         printf("+\n");
12         for(col=0; col<m; col++) printf("|   ");
13         printf("|\n");        
14     }
15     
16     printf("+");
17     _____________________________;   //填空
18     printf("\n");
19 }
20 
21 int main()
22 {
23     f(10,4);
24     return 0;
25 }

注意:僅僅填寫划線部分缺少的內容,不要添加任何已有內容或說明性文字。

思路:填空的地方注釋掉輸出一看就知道填寫啥了。

答案:

for(col=0; col<m; col++) printf("---+");

 

5.快速排序

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

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

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

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

 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 }
47 
48 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);

 

6.湊算式

     B      DEF
A + --- + ------- = 10
     C      GHI

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

這個算式中A~I代表1~9的數字,不同的字母代表不同的數字。

比如:
6+8/3+952/714 就是一種解法,
5+3/1+972/486 是另一種解法。

這個算式一共有多少種解法?

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

思路:拉成一維數組全排練+判斷,值得注意的是B/C和DEF/GHI都是整除。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
 5 
 6 bool check() {
 7     int x = a[3]*100 + a[4]*10 + a[5];
 8     int y = a[6]*100 + a[7]*10 + a[8];
 9     if((a[1]*y+a[2]*x)%(a[2]*y) != 0) return false;
10     int t = a[0] + (a[1]*y+a[2]*x)/(a[2]*y);
11     if(t == 10) return true;
12     return false;
13 }
14 
15 int main() {
16     int Ans = 0;
17     do {
18         if(check()) Ans++;
19     }while(next_permutation(a, a+9));
20     printf("%d\n", Ans);
21     return 0;
22 }
6.湊算式

答案:29

 

7.寒假作業

現在小學的數學題目也不是那么好玩的。
看看這個寒假作業:

□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果顯示不出來,可以參見【圖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 }
38 
39 6.寒假作業
7.寒假作業

答案:64

 

8.冰雹數

任意給定一個正整數N,
如果是偶數,執行: N / 2
如果是奇數,執行: N * 3 + 1

生成的新的數字再執行同樣的動作,循環往復。

通過觀察發現,這個數字會一會兒上升到很高,
一會兒又降落下來。
就這樣起起落落的,但最終必會落到“1”
這有點像小冰雹粒子在冰雹雲中翻滾增長的樣子。

比如N=9
9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
可以看到,N=9的時候,這個“小冰雹”最高沖到了52這個高度。

輸入格式:
一個正整數N(N<1000000)
輸出格式:
一個正整數,表示不大於N的數字,經過冰雹數變換過程中,最高沖到了多少。

例如,輸入:
10
程序應該輸出:
52

再例如,輸入:
100
程序應該輸出:
9232

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

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

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

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

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

思路:這題很坑,這個N和上面的N不一樣,答案是要求1-N這N個數在執行過程中的最大數,不單單只是一個N。記得開long long,不然會溢出。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 typedef long long LL;
 5 
 6 LL work(LL x) {
 7     LL Max = x;
 8     while(x != 1) {
 9         if(x%2) x = 3 * x + 1;
10         else x /= 2;
11         Max = max(Max, x);
12     }
13     return Max;
14 }
15 
16 int main() {
17     LL N, Ans=0; cin >> N;
18     for(LL i=1; i<=N; ++i) {
19         LL tmp = work(i);
20         Ans = max(Ans, tmp);
21     }
22     printf("%lld\n", Ans); 
23     return 0;
24 }
9.冰雹數

 

9.卡片換位

你玩過華容道的游戲嗎?
這是個類似的,但更簡單的游戲。
看下面 3 x 2 的格子

+---+---+---+
| A | * | * |
+---+---+---+
| B | | * |
+---+---+---+

在其中放5張牌,其中A代表關羽,B代表張飛,* 代表士兵。
還有一個格子是空着的。

你可以把一張牌移動到相鄰的空格中去(對角不算相鄰)。
游戲的目標是:關羽和張飛交換位置,其它的牌隨便在哪里都可以。

輸入格式:
輸入兩行6個字符表示當前的局面

輸出格式:
一個整數,表示最少多少步,才能把AB換位(其它牌位置隨意)

例如,輸入:
* A
**B

程序應該輸出:
17

再例如,輸入:
A B
***

程序應該輸出:
12


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

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

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

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

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

思路:寬搜題,注釋寫的很詳細。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 char Map[5][5];
 5 int x_p, y_p, x_a, y_a, x_b, y_b;
 6 bool vis[3][3][3][3][3][3]; // 方便檢測新得到的狀態之前有沒有添加過 
 7 int u[4] = {-1, 0, 0, 1}, v[4] = {0, -1, 1, 0};
 8 
 9 struct Node { // 定義一個狀態  
10     int p_x, p_y; // 空格的坐標 
11     int a_x, a_y; // A點坐標 
12     int b_x, b_y; // B點坐標 
13     int step;      // 初始狀態到目前的狀態所需步數 
14 };
15 
16 void bfs() {
17     queue<Node> q;
18     Node Now; // 初始狀態 
19     Now.p_x = x_p, Now.p_y = y_p;
20     Now.a_x = x_a, Now.a_y = y_a;
21     Now.b_x = x_b, Now.b_y = y_b;
22     Now.step = 0; // 步數為0  
23     q.push(Now); // 壓入隊列 
24     while(!q.empty()) { // 隊列不為空 
25         Now = q.front(); q.pop(); // 彈出隊列中的第一個狀態 
26         //if(vis[Now.a_x][Now.a_y][Now.b_x][Now.b_y][Now.p_x][Now.p_y]) continue;
27         vis[Now.a_x][Now.a_y][Now.b_x][Now.b_y][Now.p_x][Now.p_y] = true; // 這是一個新狀態 標記遇到過 
28         if(Now.a_x==x_b && Now.a_y==y_b && Now.b_x==x_a && Now.b_y==y_a) { // A B兩點已經交換了 輸出 
29             printf("%d\n", Now.step);
30             return ;
31         }
32         for(int i=0; i<4; ++i) { // 空格向四個方向走 
33             int x = Now.p_x + u[i];
34             int y = Now.p_y + v[i];
35             if(x<0 || x>1 || y<0 || y>2) continue; // 越界 
36             Node End = Now; // 空格向四個方向走后的狀態 
37             End.p_x = x, End.p_y = y, End.step++; // 更新空格的位置 
38             if(x==Now.a_x && y==Now.a_y) // 交換的是A A的新位置就是上一個狀態的空格位置 
39                 End.a_x = Now.p_x, End.a_y = Now.p_y;
40             if(x==Now.b_x && y==Now.b_y) // 交換的是B B的新位置就是上一個狀態的空格位置 
41                 End.b_x = Now.p_x, End.b_y = Now.p_y;
42             if(vis[End.a_x][End.a_y][End.b_x][End.b_y][End.p_x][End.p_y]) // 這種情況添加過了 
43                 continue;
44             q.push(End); // 把新的情況添加進去 
45         }
46     }
47 }
48 
49 int main() {
50     for(int i=0; i<2; ++i) // 讀入
51         gets(Map[i]);
52     for(int i=0; i<2; ++i)
53         for(int j=0; j<3; ++j) { // 查找空格、A、B的位置 
54             if(Map[i][j] == ' ')
55                 x_p = i, y_p = j;
56             if(Map[i][j] == 'A')
57                 x_a = i, y_a = j;
58             if(Map[i][j] == 'B')
59                 x_b = i, y_b = j;
60         }
61     memset(vis, false, sizeof(vis));
62     bfs();
63     return 0;
64 }
9.卡片換位

 

10.密碼脫落

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.密碼脫落-方法二

 


免責聲明!

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



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