藍橋杯第七屆 省賽 c語言A組

第一題

網友年齡

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

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

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

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

【思路】

寫一個循環即可解決問題。

答案:7

#include <iostream>
using namespace std;

int main() {
	int rec = 0, note;
	for (int i = 1; i <= 99; i++) {
		note = (i%10)*10 + i/10;
		if (i - note == 27)
			rec++;
	}
	cout << rec << endl;
	return 0;
}

 

第二題

生日蠟燭

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

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

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

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

【思路】

由於是填空題,用了兩個簡單的循環。

答案:26

#include <iostream>
using namespace std;

int main() {
	int rec, t;
	for (int i = 1; i <= 100; i++) {
		rec = 0;
		t = i;
		while (rec < 236) {
			rec += t;
			t++;
		}
		if (rec == 236) {
			cout << i << endl;
			break;
		}
	}
	return 0;
}

 

第三題

方格填數

如下的10個格子

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

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

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

【思路】

把所有的情況枚舉一遍,把不連續的要求全部列出來,同時滿足則找到一種方案。

答案:1580

#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;

bool cn(string s) {
	if (abs(s[0]-s[1]) != 1 && abs(s[0]-s[3]) != 1 && abs(s[0]-s[4]) != 1 && abs(s[0]-s[5]) != 1 &&
		abs(s[1]-s[2]) != 1 && abs(s[1]-s[4]) != 1 && abs(s[1]-s[5]) != 1 && abs(s[1]-s[6]) != 1 &&
		abs(s[2]-s[5]) != 1 && abs(s[2]-s[6]) != 1 &&
		abs(s[3]-s[4]) != 1 && abs(s[3]-s[7]) != 1 && abs(s[3]-s[8]) != 1 &&
		abs(s[4]-s[5]) != 1 && abs(s[4]-s[7]) != 1 && abs(s[4]-s[8]) != 1 && abs(s[4]-s[9]) != 1 &&
		abs(s[5]-s[6]) != 1 && abs(s[5]-s[8]) != 1 && abs(s[5]-s[9]) != 1 &&
		abs(s[6]-s[9]) != 1 && abs(s[7]-s[8]) != 1 && abs(s[8]-s[9]) != 1)
		return true;
	else
		return false;
}

int main() {
	string s = "0123456789";
	int rec = 0;
	do {
		if (cn(s)) rec++;
	} while (next_permutation(s.begin(), s.end()));
	cout << rec << endl;
	
	return 0;
}

 

第四題

快速排序

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

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

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

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

#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);
    }
    ________________________;
    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;
}


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

【思路】

瞭解快排的同學應該清楚,最終的目標是將"標尺"放到適當的位置,由於這個程序選擇的"標尺"在排序的左邊,所以應該拿"標尺"與小於"標尺"的最右邊的元素交換。

答案:swqp(a,p,j)

 

第五題

消除尾一

下面的代碼把一個整數的二進制表示的最右邊的連續的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 = ___________;
	
	for(i=0; i<32; i++) printf("%d", (x>>(31-i))&1);
	printf("\n");	
}

int main()
{
	f(103);
	f(12);
	return 0;
}

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

【思路】

一個二進制數,加1,末位連續的1全爲0,進位加1,再與原來的數進行與操作,得到結果。

答案:x&(x+1)

 

第六題

寒假作業

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

   □ + □ = □
   □ - □ = □
   □ × □ = □
   □ ÷ □ = □


每個方塊代表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

就算兩種解法。(加法,乘法交換律後算不同的方案)
 
你一共找到了多少種方案?


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

【思路】

深搜+剪枝,別人的思路,剪枝剪得很妙,贊一個!(又學到東西了,開心。)

答案:64

#include <iostream>
#include <cstring>
using namespace std;

int visit[13], a[12];
int rec = 0;

void dfs(int t) {
	if (t >= 3 && a[0] + a[1] != a[2])  //剪枝
		return ;
	if (t >= 6 && a[3] - a[4] != a[5])
		return ;
	if (t >= 9 && a[6] * a[7] != a[8])
		return ;
	if (t >= 12 && a[9] == a[10] * a[11]) {
		rec++;
		return ;
	}
	if (t >= 12)
		return;
	for (int i = 1; i <= 13; i++) {
		if (!visit[i]) {
			visit[i] = 1;
			a[t] = i;
			dfs(t+1);
			visit[i] = 0;
		}
	}
}

int main() {
	memset(a, 0, sizeof(a));
	memset(visit, 0, sizeof(visit));
	dfs(0);
	cout << rec << endl;
	
	return 0;
}

 

第七題

剪郵票

有12張連在一起的12生肖的郵票。
現在你要從中剪下5張來,要求必須是連着的。
(僅僅連接一個角不算相連)
比如,

中,粉紅色所示部分就是合格的剪取。

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

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

【思路】

參考別人的思路。

1.遍歷所有的方案

2.每個方案利用深搜判斷是否鏈接,鏈接則方案數加一

重點在於深搜的設計。

首先存儲到某個方案,調用深搜,dfs()函數遍歷到某個點,判斷它周圍的四個點是否在方案裏面,如果在方案裏面,且該點未曾被遍歷到,則標記該點被遍歷。

可以利用每個點的數值得到周圍的四個點,但由於4和5不相連,8和9不相連,改變方格的值爲:

1     2    3    4

6     7    8    9

11  12  13  14

這樣,每個點遍歷上下左右的點的距離分別爲{-5,+5,-1,+1}

纖細設計兄弟們去體會下代碼吧。。。我盡力了。

#include <iostream>
#include <cstring>
using namespace std;

const int num = 5;
int a[num], visit[num], t;
int map[] = {1,2,3,4,6,7,8,9,11,12,13,14};
int b[] = {-1, 1, -5, 5};

void dfs(int n) {
    for (int i = 0; i < 4; i++) { //嘗試當前點的四個方向
        t = a[n] + b[i];
        if (t == 5 || t == 10 || t > 14 || t < 1) //t的值不在表格內,遍歷下一個方向
            continue;
        for (int j = 0; j < 5; j++) 
            if (!visit[j] && t == a[j]) { //當前點的某一個方向的點在當前方案中
                visit[j] = 1;
                dfs(j);
            }
    }
}

int main(){
    bool flag;
    int rec = 0;
    for (int i = 0; i < 12; i++) 
        for (int j = i + 1; j < 12; j++)
            for (int k = j + 1; k < 12; k++)
                for (int l = k + 1; l < 12; l++)
                    for (int n = l + 1; n < 12; n++) {
                        a[0] = map[i];
                        a[1] = map[j];
                        a[2] = map[k];
                        a[3] = map[l];
                        a[4] = map[n];
                        memset(visit, 0, sizeof(visit));
                        dfs(0);
                        flag = true;
                        for (int m = 0; m < num; m++)
                            if (!visit[m]) {
                                flag = false;
                                break;
                            }
                        if (flag == true)
                            rec ++;
                     }
    cout << rec << endl;

    return 0;
}

 

第八題

四平方和

四平方和定理,又稱爲拉格朗日定理:
每個正整數都可以表示爲至多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>, 不能通過工程設置而省略常用頭文件。

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

【思路】

暴力破解,枚舉4個數,符合條件結束程序,用三個循環即可,第四個數直接計算出來,降低時間複雜度。

#include <iostream>
#include <cmath>
using namespace std;
const int NUM = 5000000;

int main(){
    int num = sqrt(5000000);
    int n, d;
    bool flag = false;
    cin >> n;
    for (int a = 0; a <= num; a++)  
        for (int b = 0; b <= num; b++)  
            for (int c = 0; c <= num; c++) { 
                d = sqrt(n - (a * a + b * b + c * c));
                if (n == a * a + b * b + c * c + d * d) {
                    if (c > d) {
                        int temp = c;
                        c = d;
                        d = temp;
                    }

                    cout << a << ' ' << b << ' ' << c << ' ' << d << endl; 

                    return 0;
                }
            }
}

 

這裏呈上別人的思路。用一個數組存儲所有小於n的數中能被2個數的平方和求得的數。從這些數中找出符合條件的數即可,具體實現看代碼。這種方法有效地減低了時間複雜度,但是需要消耗更多的內存。

#include <iostream>
#include <cmath>
using namespace std;

const int NUM = 5000010;

int map[NUM] = {0};
int n;

void f() {
    for (int i = 0; i * i <= n; i++)
        for (int j = 0; j * j <= n; j++) 
            if (i * i + j * j <= n)
                map[i * i + j * j] = 1; //這個數可以用兩個數平方求得
                
}


int main(){
    cin >> n;
    f();
    for (int i = 0; i * i <= n; i++) {
        for (int j = 0; j * j <= n; j++) {
            if (map[n - i * i - j * j] == 0)
                continue;
            for (int k = 0; k * k <= n; k++)  {
                int p = sqrt(n - i * i - j * j - k * k);
                if ((i * i + j * j + k * k + p * p) == n) {
                    cout << i << ' ' << j  << ' ' << k << ' ' << p << endl;
                    return 0;
                }
            }
        }
    }
}

 

第九題

密碼脫落

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

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

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

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

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

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

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

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

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

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

【思路】

很慚愧還是大神的思路,源博主找不到了,因爲看的博客沒有標明,學習一下。

用的方法還是我們熟悉的深搜,但是我覺得需要在充分了解題目的基礎上,才能知道用這樣的判斷可以得到答案。。。

#include <iostream>
#include <string>
using namespace std;

int num = 100000;
string str;

void dfs(int l, int r, int len) {
    if (l >= r) 
        num = (num < len ? num : len);
    else {
        if (str[l] == str[r])
            dfs(l + 1, r - 1, len);
        else {
            dfs(l + 1, r, len + 1);
            dfs(l, r - 1, len + 1);
        }
    } 
    return ;
}
    

int main(){

    cin >> str;

    dfs(0, str.size() - 1, 0);

    cout << num << endl;

    return 0;
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章