1. 程式人生 > >2013第四屆 藍橋杯c/c++B組預賽 解題報告

2013第四屆 藍橋杯c/c++B組預賽 解題報告

大半部分題目都是自己做的,可能還有存在錯誤的地方,還望各位指正

有不會的題目,還請大牛們留下解題思路,謝謝了。

第一題:高斯日記

大數學家高斯有個好習慣:無論如何都要記日記。他的日記有個與眾不同的地方,他從不註明年月日,而是用一個整數代替,比如:4210後來人們知道,那個整數就是日期,它表示那一天是高斯出生後的第幾天。這或許也是個好習慣,它時時刻刻提醒著主人:日子又過去一天,還有多少時光可以用於浪費呢?

高斯出生於:1777430日。

    在高斯發現的一個重要定理的日記上標註著:5343,因此可算出那天是:17911215日。

高斯獲得博士學位的那天日記上標著:8113   

請你算出高斯獲得博士學位的年月日。

提交答案的格式是:yyyy-mm-dd, 例如:1980-03-21

解題:

這道題比較簡單,記得當時筆算加程式輔助就算出來了。

答案: 1799-07-16

第二題:馬虎的算式

小明是個急性子,上小學的時候經常把老師寫在黑板上的題目抄錯了。

有一次,老師出的題目是:36 x 495 = ?

他卻給抄成了:396 x 45 = ?

但結果卻很戲劇性,他的答案竟然是對的!!

因為 36 * 495 = 396 * 45 = 17820

類似這樣的巧合情況可能還有很多,比如:27 * 594 = 297 * 54

假設 a b c d e 代表1~9不同的5個數字(注意是各不相同的數字,且不含0

能滿足形如: ab * cde = adb * ce 這樣的算式一共有多少種呢?

請你利用計算機的優勢尋找所有的可能,並回答不同算式的種類數。

滿足乘法交換律的算式計為不同的種類,所以答案肯定是個偶數。

解題:由於是填空題,就時間和空間就無所謂了。直接迴圈出結果。

答案:142

第三題:39級臺階

    小明剛剛看完電影《第39級臺階》,離開電影院的時候,他數了數禮堂前的臺階數,恰好是39!

    站在臺階前,他突然又想著一個問題:

    如果我每一步只能邁上1個或2個臺階。先邁左腳,然後左右交替,最後一步是邁右腳,也就是說一共要走偶數步。那麼,上完39級臺階,有多少種不同的上法呢?

    請你利用計算機的優勢,幫助小明尋找答案。

要求提交的是一個整數。

注意:不要提交解答過程,或其它的輔助說明文字。

#include<stdio.h> 
#include<stdlib.h>
#include<iostream>
using namespace std;

int count = 0;

void dfs(int sum , int step)
{
	if(sum == 39)
	{
		if(step % 2 == 0)
		{
			count++;
			return;
		}
		else return;
	}
	else if(sum > 39) return;	
	else
	{
		dfs(sum+1, step+1);
		dfs(sum+2, step+1);
	}
}

int main()
{
	dfs(0 , 0);
	cout<<count<<endl;
	return 0;
}

答案:51167078

第四題:黃金連分數

黃金分割數0.61803... 是個無理數,這個常數十分重要,在許多工程問題中會出現。有時需要把這個數字求得很精確。

對於某些精密工程,常數的精度很重要。也許你聽說過哈勃太空望遠鏡,它首次升空後就發現了一處人工加工錯誤,對那樣一個龐然大物,其實只是鏡面加工時有比頭髮絲還細許多倍的一處錯誤而已,卻使它成了“近視眼”!!

    言歸正傳,我們如何求得黃金分割數的儘可能精確的值呢?有許多方法。

    比較簡單的一種是用連分數:

                  1

    黃金數 = ---------------------

                        1

             1 + -----------------

                          1

                 1 + -------------

                            1

                     1 + ---------

                          1 + ...

    這個連分數計算的“層數”越多,它的值越接近黃金分割數。

    請你利用這一特性,求出黃金分割數的足夠精確值,要求四捨五入到小數點後100位。

    小數點後3位的值為:0.618

    小數點後4位的值為:0.6180

    小數點後5位的值為:0.61803

    小數點後7位的值為:0.6180340

   (注意尾部的0,不能忽略)

你的任務是:寫出精確到小數點後100位精度的黃金分割值。

注意:尾數的四捨五入! 尾數是0也要保留!

顯然答案是一個小數,其小數點後有100位數字,請通過瀏覽器直接提交該數字。

注意:不要提交解答過程,或其它輔助說明類的內容。

自己算完之後,看了很多網上的答案,感覺都不太一樣,我也不知道最後是誰的正確。

第五題:字首判斷

    如下的程式碼判斷 needle_start指向的串是否為haystack_start指向的串的字首,如不是,則返回NULL

    比如:"abcd1234" 就包含了 "abc" 為字首

 1 char* prefix(char* haystack_start, char* needle_start)
 2 {
 3     char* haystack = haystack_start;
 4     char* needle = needle_start;
 5 
 6     
 7     while(*haystack && *needle){
 8         if(______________________________) return NULL;  //填空位置
 9     }
10     
11     if(*needle) return NULL;
12     
13     return haystack_start;
14 }

請分析程式碼邏輯,並推測劃線處的程式碼,通過網頁提交。

注意:僅把缺少的程式碼作為答案,千萬不要填寫多餘的程式碼、符號或說明文字!!

解題:*(haystack++) != *(needle++)

第六題:三部排序

    一般的排序有許多經典演算法,如快速排序、希爾排序等。

    但實際應用時,經常會或多或少有一些特殊的要求。我們沒必要套用那些經典演算法,可以根據實際情況建立更好的解法。

    比如,對一個整型陣列中的數字進行分類排序:

    使得負數都靠左端,正數都靠右端,0在中部。注意問題的特點是:負數區域和正數區域內並不要求有序。可以利用這個特點通過1次線性掃描就結束戰鬥!!

    以下的程式實現了該目標。

    其中x指向待排序的整型陣列,len是陣列的長度。

 1 void sort3p(int* x, int len)
 2 {
 3     int p = 0;
 4     int left = 0;
 5     int right = len-1;
 6     
 7     while(p<=right){
 8         if(x[p]<0){
 9             int t = x[left];
10             x[left] = x[p];
11             x[p] = t;
12             left++;
13             p++;
14         }
15         else if(x[p]>0){
16             int t = x[right];
17             x[right] = x[p];
18             x[p] = t;
19             right--;            
20         }
21         else{
22             __________________________;  //填空位置
23         }
24     }
25     
26 }

如果給定陣列:

   25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0

   則排序後為:

   -3,-2,-16,-5,0,0,0,21,19,33,25,16,18,25

請分析程式碼邏輯,並推測劃線處的程式碼,通過網頁提交

注意:僅把缺少的程式碼作為答案,千萬不要填寫多餘的程式碼、符號或說明文字!!

解題:

對於這道題,極其的暈乎,比賽的時候怎麼想也沒有想出來,所以就用了一個比較水的程式碼,不知道是對是錯,但是測了幾個資料,還可以過。以下程式碼純屬自己留念,要看就看下面的正解吧。

比賽時提交的程式碼(忽略即可):

 1 int temp=p;
 2 
 3 while(p<=right)
 4 
 5 {if(!x[temp])temp++;
 6 
 7 else break;
 8 
 9 }
10 
11 if(temp>right)
12 
13 break;
14 
15 else
16 
17 {
18 
19 int t;
20 
21 t=x[temp];
22 
23 x[temp]=x[p];
24 
25 x[p]=t;
26 
27 }
View Code

正解: p++

第七題:錯誤票據

    某涉密單位下發了某種票據,並要在年終全部收回。

    每張票據有唯一的ID號。全年所有票據的ID號是連續的,但ID的開始數碼是隨機選定的。

    因為工作人員疏忽,在錄入ID號的時候發生了一處錯誤,造成了某個ID斷號,另外一個ID重號。

    你的任務是通過程式設計,找出斷號的ID和重號的ID

    假設斷號不可能發生在最大和最小號。

要求程式首先輸入一個整數N(N<100)表示後面資料行數。

接著讀入N行資料。

每行資料長度不等,是用空格分開的若干個(不大於100個)正整數(不大於100000

每個整數代表一個ID號。

要求程式輸出1行,含兩個整數m n,用空格分隔。

其中,m表示斷號IDn表示重號ID

例如:

使用者輸入:

2

5 6 8 11 9 

10 12 9

則程式輸出:

7 9

再例如:

使用者輸入:

6

164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196

172 189 127 107 112 192 103 131 133 169 158 

128 102 110 148 139 157 140 195 197

185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190

149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188

113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119

則程式輸出:

105 120

資源約定:

峰值記憶體消耗 < 64M

CPU消耗  < 1000ms

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

所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。

注意: main函式需要返回0

注意只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。

注意所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。

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

解題:

當時一直錯誤,花了好長的時間才測試出來,看來以後還得認真+認真。

 1 #include<iostream>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 char st[105][110];
 7 int num[150];
 8 int vis[100100];
 9 int main()
10 {
11     int n , temp , count = 0 , min = 200000 , max = 0 , m;
12     int i , j;
13     char ch[8];
14     cin>>n;
15     memset(vis , 0 , sizeof(vis));
16     getchar();
17     for(i = 0; i < n; i++)
18     {
19         gets(st[i]);
20     }
21     temp = i -1;
22     for(i = temp; i >=0; i--)
23     {
24         j = 0;
25         char *p = st[i];
26         while(*p!='\0')
27         {
28             if(*p >= '0' && *p <= '9')
29             {
30                 ch[j++] = *p;
31             }
32             else
33             {
34                 ch[j] = '\0';
35                 m = atoi(ch);
36                 if(m == 0){p++; continue;}
37                 vis[m]++;
38                 j = 0;
39                 if(min > m) min = m;
40                 if(max < m) max = m;
41             }
42             p++;
43         }
44         if(*(p-1) != ' ')
45         {
46             ch[j] = '\0';
47             m = atoi(ch);
48             if(m == 0){p++; continue;}
49             vis[m]++;
50             j = 0;
51             if(min > m) min = m;
52             if(max < m) max = m;
53         }
54     }
55     int a , b , flag = 0;
56     for(i = min; i <= max; i++)
57     {
58         if(!vis[i]){a = i; flag++;}
59         if(vis[i] == 2){b = i; flag++;}
60         if(flag==2)break;
61     }
62     cout<<a<<' '<<b<<endl;
63     return 0;
64 }
View Code

第八題:翻硬幣

    小明正在玩一個“翻硬幣”的遊戲。

    桌上放著排成一排的若干硬幣。我們用 表示正面,用 表示反面(是小寫字母,不是零)。

    比如,可能情形是:**oo***oooo

    如果同時翻轉左邊的兩個硬幣,則變為:oooo***oooo

    現在小明的問題是:如果已知了初始狀態和要達到的目標狀態,每次只能同時翻轉相鄰的兩個硬幣,那麼對特定的局面,最少要翻動多少次呢?

    我們約定:把翻動相鄰的兩個硬幣叫做一步操作,那麼要求:

程式輸入:

兩行等長的字串,分別表示初始狀態和要達到的目標狀態。每行的長度<1000

程式輸出:

一個整數,表示最小操作步數

例如:

使用者輸入:

**********

o****o****

程式應該輸出:

5

再例如:

使用者輸入:

*o**o***o***

*o***o**o***

程式應該輸出:

1

資源約定:

峰值記憶體消耗 < 64M

CPU消耗  < 1000ms

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

所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。

注意: main函式需要返回0

注意只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。

注意所有依賴的函式必須明確地在原始檔中 #include <xxx>, 不能通過工程設定而省略常用標頭檔案。

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

解題:

最近一直在做廣搜的題目,看到這道題異常的激動,果斷用廣搜來解決。然而比賽結束之後,才發現對於比較大的測試資料果斷超時。

經過高人的指點,終於有了這麼簡單的思路。就是把初始狀態和最終狀態的兩個字串進行比較,相同為1,不同為0,將01序列存放在一個數組中,然後開始遍歷陣列,如果發現0,就把相鄰的兩個數字翻轉(即1->0 , 0 - > 1),順便記錄翻轉的次數就ok了。

唉,如此的簡單~~~~~~~~

廣搜+佇列解題程式碼:

 1 #include<iostream>
 2 #define MAX 1000
 3 #include<queue>
 4 #include<string.h>
 5 using namespace std;
 6 
 7 typedef struct
 8 {
 9     char st[MAX];
10     int step;
11 }state;
12 char vis[MAX*MAX][MAX];
13 int Count  = 0;
14 int compare(state temp)
15 {
16     int i , flag = 0;
17     for(i = 0; i < Count; i++)
18     {
19         if(!strcmp(temp.st , vis[i]))
20         {
21             flag = 1;
22             return 0;
23         }
24     }
25     if(!flag)
26     {
27         strcpy(vis[Count++] , temp.st);
28         return 1;
29     }
30 }
31 int bfs(state &temp , int i)
32 {
33     if(temp.st[i] == '*')
34         temp.st[i] = 'o';
35     else temp.st[i] = '*';
36     if(temp.st[i+1] == '*')
37         temp.st[i+1] = 'o';
38     else temp.st[i+1] = '*';
39     temp.step++;
40     return 1;
41 }
42 int main()
43 {
44     int i , len;
45     queue<state>q;
46     state start;
47     char st1[MAX] , st2[MAX];
48     gets(st1);
49     gets(st2);
50     strcpy(start.st , st1);
51     start.step = 0;
52     q.push(start);
53     len = strlen(st1);
54     while(!q.empty())
55     {
56         state temp1;
57         temp1 = q.front();
58         q.pop();
59         if(!strcmp(temp1.st , st2)) 
60         {
61             cout<<temp1.step<<endl;
62             break;
63         }
64         for(i = 0; i < len-1; i++)
65         {
66             state temp2 = temp1;
67             if(bfs(temp2 , i))
68             {
69                 if(!compare(temp2)) continue;
70                 else q.push(temp2);
71             }
72         }
73     }
74     return 0;
75 }
View Code

第二種解題方法:

 1 #include<iostream>
 2 #define maxn 2000
 3 #include<string.h>
 4 using namespace std;
 5 
 6 char st1[maxn] , st2[maxn];  //盛放輸入字串
 7 int change[maxn];   //儲存0、1的陣列
 8 int main()
 9 {
10     int len , num = 0;
11     int i , j;
12     gets(st1);
13     gets(st2);
14     len = strlen(st1);
15     for(i = 0; i < len; i ++)   //相同存1,不同存0
16     {
17         if(st1[i] == st2[i]) change[i] = 1;
18         else change[i] = 0;
19     }
20     for(i = 0; i < len; i++)
21     {
22         if(!change[i])   //如果該位初始和最終的硬幣狀態不一樣
23         {
24             change[i] = 1;   //相鄰的硬幣翻轉
25             change[i+1] = change[i+1]==0 ? 1 : 0;
26             num++;
27         }
28     }
29     printf("%d\n" , num);
30     return 0;
31 }
View Code

第九題