第七屆藍橋杯大賽個人賽省賽C語言A組題目答案
阿新 • • 發佈:2019-01-08
第七屆省賽題目
注意
- 簡單的題目,只是寫了一個函式實現功能,對於複雜的題目,會給出全部程式碼
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; }