藍橋杯--2013第四屆C/C++C組省賽

題目標題: 猜年齡


    美國數學家維納(N.Wiener)智力早熟,11歲就上了大學。他曾在1935~1936年應邀來中國清華大學講學。

    一次,他參加某個重要會議,年輕的臉孔引人注目。於是有人詢問他的年齡,他回答說:

    “我年齡的立方是個4位數。我年齡的4次方是個6位數。這10個數字正好包含了從0到9這10個數字,每個都恰好出現1次。”

    請你推算一下,他當時到底有多年輕。

    通過瀏覽器,直接提交他那時的年齡數字。
    注意:不要提交解答過程,或其它的說明文字。

答案:18

#include <bits/stdc++.h>

using namespace std;

int vis[10];

bool Judge (int k) {
	int a = k*k*k;
	int b = k*k*k*k;
	if (a >=1000 && a <= 9999 && b >= 100000 && b <= 999999) {
		memset(vis, 0, sizeof(vis));
		for (int i = 0; i < 4; i++) {
			vis[a%10]++;
			a /= 10;
		}
		for (int i = 0; i < 6; i++) {
			vis[b%10]++;
			b /= 10;
		}
		for (int i = 0; i < 10; i++) {
			if (vis[i] != 1) {
				return false;
			}
		}
		return true;
	}
	return false;
}

int main() {
	for (int i = 10; i <= 99; i++) {
		if (Judge(i)) {
			printf("%d\n",i);
		}
	}//18
	return 0;
}

標題: 馬虎的算式


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

    有一次,老師出的題目是: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(暴力枚舉)


標題: 振興中華

    小明參加了學校的趣味運動會,其中的一個項目是:跳格子。

    地上畫着一些格子,每個格子裏寫一個字,如下所示:(也可參見p1.jpg)

從我做起振
我做起振興
做起振興中
起振興中華


    比賽時,先站在左上角的寫着“從”字的格子裏,可以橫向或縱向跳到相鄰的格子裏,但不能跳到對角的格子或其它位置。一直要跳到“華”字結束。


    要求跳過的路線剛好構成“從我做起振興中華”這句話。

    請你幫助小明算一算他一共有多少種可能的跳躍路線呢?

答案是一個整數,請通過瀏覽器直接提交該數字。
注意:不要提交解答過程,或其它輔助說明類的內容。

答案:35(遞推或者直接搜索編碼一下)

dp[i][j] = dp[i-1][j] + dp[i][j-1] (dp[0][i] = dp[i][0] = 1)

#include <bits/stdc++.h>

using namespace std;

/*
從我做起振
我做起振興
做起振興中
起振興中華
*/

char img[5][6]={
"12345",
"23456",
"34567",
"45678"
};

int nxt[2][2] = {0,1,1,0};

int DFS(int x, int y, char bef) {
	if (x == 3 && y == 4) {
		return 1;
	}
	int ans = 0;
	for (int i = 0; i < 2; i++) {
		int nx = x + nxt[i][0];
		int ny = y + nxt[i][1];
		if (x > 3 || x < 0 || y > 4 || y < 0) {
			continue;
		}
		if (img[nx][ny] == img[x][y] + 1) {
			ans += DFS(nx, ny, img[nx][ny]);
		}
	}
	return ans ;
}

int main() {
	cout << DFS(0, 0, '0') << endl;
	return 0;
}

標題: 幻方填空

    幻方是把一些數字填寫在方陣中,使得行、列、兩條對角線的數字之和都相等。

    歐洲最著名的幻方是德國數學家、畫家迪勒創作的版畫《憂鬱》中給出的一個4階幻方。

    他把1,2,3,...16 這16個數字填寫在4 x 4的方格中。

    如圖p1.jpg所示,即:

16 ?  ?  13
?  ?  11 ?
9  ?  ?  *
?  15 ?  1

    表中有些數字已經顯露出來,還有些用?和*代替。

    請你計算出? 和 * 所代表的數字。並把 * 所代表的數字作爲本題答案提交。


答案是一個整數,請通過瀏覽器直接提交該數字。
注意:不要提交解答過程,或其它輔助說明類的內容。

答案:暴力搜索一下,或者可以利用幻方的構造方法直接手算,搜索的話注意編碼一下,搜10個數就夠了,也就是搜索深度只有10

#include <bits/stdc++.h>

using namespace std;

int val[16],vis[17],dis[16];

bool Judge () {
	int sum[2][4],b,c;
	b = c = 0;
	memset(sum, 0, sizeof(sum));
	for (int i = 0; i < 2; i++) {
		for (int j = 0; j < 4; j++) {
			for (int k = 0; k < 4; k++) {
				if (i == 0) {
					sum[i][j] += val[j*4+k];
				}else {
					sum[i][j] += val[j+k*4];
				}
			}
			if (sum[i][j] != sum[0][0]) {
				return false;
			}
		}
	}
	
	for (int i = 0; i < 4; i++) {
		b += val[i*5];
		c += val[3+3*i];
	}
	if (b != sum[0][0] || c != sum[0][0]) {
		return false;
	}
	return true;
}

void DFS (int idx) {
	if (idx == 16) {
		if (Judge()) {
			cout << val[11] << endl;
			system("pause");
		}
		return ;
	}
	if (dis[idx] == 1) {
		DFS(idx+1);
	}else {
		for (int i = 1; i <= 16; i++) {
			if (vis[i] == 0) {
				vis[i] = 1;
				dis[idx] = 1;
				val[idx] = i;
				DFS(idx+1);
				dis[idx] = 0;
				vis[i] = 0;
			}
		}
	}
}

int main() {
	memset(dis, 0, sizeof(dis));
	memset(vis, 0, sizeof(vis));
	val[0] = 16; dis[0] = 1; vis[16] = 1;
	val[3] = 13; dis[3] = 1; vis[13] = 1;
	val[6] = 11; dis[6] = 1; vis[11] = 1;
	val[8] = 9; dis[8] = 1; vis[9] = 1;
	val[13] = 15; dis[13] = 1; vis[15] = 1;
	val[15] = 1; dis[15] = 1; vis[1] = 1;
	DFS(0); //12
	return 0;
}

題目標題:公約數公倍數

    我們經常會用到求兩個整數的最大公約數和最小公倍數的功能。

    下面的程序給出了一種算法。

    函數 myfunc 接受兩個正整數a,b

    經過運算後打印出 它們的最大公約數和最小公倍數。

    此時,調用 myfunc(15,20)  

將會輸出:
5
60 

// 交換數值
void swap(int *a,int *b)
{
   int temp;
   temp=*a;
   *a=*b;
   *b=temp;
}

void myfunc(int a, int b)
{
   int m,n,r;  
   if(a<b) swap(&a,&b);
   m=a;n=b;r=a%b;
   while(r!=0)
   {
    a=b;b=r;
    r=a%b;
   }
   printf("%d\n",b);  // 最大公約數 
   printf("%d\n", ____________________________________);  // 最小公倍數 
}


請分析代碼邏輯,並推測劃線處的代碼,通過網頁提交。
注意:僅把缺少的代碼作爲答案,千萬不要填寫多餘的代碼、符號或說明文字!!

答案:n*m/b


標題:三部排序

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

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

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

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

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

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

void sort3p(int* x, int len)
{
	int p = 0;
	int left = 0;
	int right = len-1;
	
	while(p<=right){
		if(x[p]<0){
			int t = x[left];
			x[left] = x[p];
			x[p] = t;
			left++;
			p++;
		}
		else if(x[p]>0){
			int t = x[right];
			x[right] = x[p];
			x[p] = t;
			right--;			
		}
		else{
			__________________________;  //填空位置
		}
	}
	
}

   如果給定數組:
   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
	


請分析代碼邏輯,並推測劃線處的代碼,通過網頁提交
注意:僅把缺少的代碼作爲答案,千萬不要填寫多餘的代碼、符號或說明文字!!

答案:p++


標題:核桃的數量

    小張是軟件項目經理,他帶領3個開發組。工期緊,今天都在加班呢。爲鼓舞士氣,小張打算給每個組發一袋核桃(據傳言能補腦)。他的要求是:

    1. 各組的核桃數量必須相同
    2. 各組內必須能平分核桃(當然是不能打碎的)
    3. 儘量提供滿足1,2條件的最小數量(節約鬧革命嘛)

程序從標準輸入讀入:
a b c
a,b,c都是正整數,表示每個組正在加班的人數,用空格分開(a,b,c<30)

程序輸出:
一個正整數,表示每袋核桃的數量。

例如:
用戶輸入:
2 4 5

程序輸出:
20

再例如:
用戶輸入:
3 1 1

程序輸出:
3



資源約定:
峯值內存消耗(含虛擬機) < 64M
CPU消耗  < 1000ms


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

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

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

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

最小公倍數

#include <bits/stdc++.h>

using namespace std;

int gcd(int a, int b) {
	if (b == 0) {
		return a;
	}
	return gcd(b, a%b);
}

int lcm(int a, int b) {
	return a*b/gcd(a,b);
}

int main() {
	int a,b,c;
	cin >> a >> b >> c;
	cout << lcm(a,lcm(b,c)) << endl;
	return 0;
}

題目標題:打印十字圖

    小明爲某機構設計了一個十字型的徽標(並非紅十字會啊),如下所示(可參見p1.jpg)

                     $$$$$$$$$$$$$
                     $           $
                   $$$ $$$$$$$$$ $$$
                   $   $       $   $
                   $ $$$ $$$$$ $$$ $
                   $ $   $   $   $ $
                   $ $ $$$ $ $$$ $ $
                   $ $ $   $   $ $ $
                   $ $ $ $$$$$ $ $ $
                   $ $ $   $   $ $ $
                   $ $ $$$ $ $$$ $ $
                   $ $   $   $   $ $
                   $ $$$ $$$$$ $$$ $
                   $   $       $   $
                   $$$ $$$$$$$$$ $$$
                     $           $
                     $$$$$$$$$$$$$


    對方同時也需要在電腦dos窗口中以字符的形式輸出該標誌,並能任意控制層數。
    
    爲了能準確比對空白的數量,程序要求對行中的空白以句點(.)代替。

輸入格式:
一個正整數 n (n<30) 表示要求打印圖形的層數

輸出:
對應包圍層數的該標誌。

例如:
用戶輸入:
1
程序應該輸出:
..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..

再例如:
用戶輸入:
3
程序應該輸出:
..$$$$$$$$$$$$$..
..$...........$..
$$$.$$$$$$$$$.$$$
$...$.......$...$
$.$$$.$$$$$.$$$.$
$.$...$...$...$.$
$.$.$$$.$.$$$.$.$
$.$.$...$...$.$.$
$.$.$.$$$$$.$.$.$
$.$.$...$...$.$.$
$.$.$$$.$.$$$.$.$
$.$...$...$...$.$
$.$$$.$$$$$.$$$.$
$...$.......$...$
$$$.$$$$$$$$$.$$$
..$...........$..
..$$$$$$$$$$$$$..

請仔細觀察樣例,尤其要注意句點的數量和輸出位置。


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


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

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

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

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

在這裏插入圖片描述

細節處理,注意30層的規模至少要125的大小。處理一下四個轉彎,四個直線,然後四個正方形(都是白色部分)

#include <bits/stdc++.h>

using namespace std;

int img[126][126];

void bian (int k, int x, int y) { //處理四條邊
	int dist = 4*k-2; //各個點之間的距離
	int len = 4*k-3; //各條邊之間的長度
	int nxt[4][2];
	nxt[0][0] = x - 2; nxt[0][1] = y;
	nxt[1][0] = x; nxt[1][1] = y - 2;
	nxt[2][0] = x + dist + 2; nxt[2][1] = y + dist;
	nxt[3][0] = x + dist; nxt[3][1] = y + dist + 2;

	for (int i = 1; i <= len; i++) {
		img[nxt[0][0]][nxt[0][1]+i] = 1;
		img[nxt[1][0]+i][nxt[1][1]] = 1;
		img[nxt[2][0]][nxt[2][1]-i] = 1;
		img[nxt[3][0]-i][nxt[3][1]] = 1;
	}
}

void jiao (int k, int x, int y) {  //處理四個角
	int dist = 4*k-2; //各個點的距離
	int nxt[4][2];
	nxt[0][0] = x; nxt[0][1] = y;
	nxt[1][0] = x + dist; nxt[1][1] = y;
	nxt[2][0] = x; nxt[2][1] = y + dist;
	nxt[3][0] = x + dist; nxt[3][1] = y + dist;
	
	for (int i = 0; i < 3; i++) {
		img[nxt[0][0]-i][nxt[0][1]] = 1;
		img[nxt[0][0]][nxt[0][1]-i] = 1;
		img[nxt[1][0]+i][nxt[1][1]] = 1;
		img[nxt[1][0]][nxt[1][1]-i] = 1;
		img[nxt[2][0]-i][nxt[2][1]] = 1;
		img[nxt[2][0]][nxt[2][1]+i] = 1;
		img[nxt[3][0]+i][nxt[3][1]] = 1;
		img[nxt[3][0]][nxt[3][1]+i] = 1;
	}
}

void Solution (int n, int k) {
	int x,y;
	x = 4; y = 4;
	memset(img, 0, sizeof(img));
	img[1][1] = 1;
	img[1][2] = 1;
	img[2][1] = 1;
	img[2][2] = 1;

	img[k][1] = 1;
	img[k][2] = 1;
	img[k-1][1] = 1;
	img[k-1][2] = 1;
	
	img[1][k] = 1;
	img[1][k-1] = 1;
	img[2][k] = 1;
	img[2][k-1] = 1;

	img[k][k] = 1;
	img[k][k-1] = 1;
	img[k-1][k] = 1;
	img[k-1][k-1] = 1;
	
	for (int i = n; i >= 1; i--) {
		jiao(i, x, y);
		bian(i, x, y);
		x += 2;
		y += 2;
	}
}

int main() {
	int n,guimo;
	cin >> n;
	guimo = 4*n+5;
	Solution(n, guimo);
	for (int i = 1; i <= guimo; i++) {
		for (int j = 1; j <= guimo; j++) {
			if (img[i][j] == 1) {
				printf(".");
			}else {
				printf("$");
			}
		}
		printf("\n");
	}
	return 0;
}

標題:帶分數

    100 可以表示爲帶分數的形式:100 = 3 + 69258 / 714

    還可以表示爲:100 = 82 + 3546 / 197

    注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。

    類似這樣的帶分數,100 有 11 種表示法。

題目要求:
從標準輸入讀入一個正整數N (N<1000*1000)
程序輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。
注意:不要求輸出每個表示,只統計有多少表示法!


例如:
用戶輸入:
100
程序輸出:
11

再例如:
用戶輸入:
105
程序輸出:
6


資源約定:
峯值內存消耗 < 64M
CPU消耗  < 3000ms


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

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

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

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


  

搜索+剪枝

#include <bits/stdc++.h>

using namespace std;

int N;
int val[10];

int ToInteger(int l, int r) {
	int res = 0;
	for (int i = l; i < r; i++) {
		res = res*10 + val[i];
	}
	return res;
}

int DFS (int idx) {
	if (idx == 9) {
		int cnt = 0;
		int A,B,C,goal;
		for (int i = 1; i < 9; i++) {
			goal = N;
			A = ToInteger(0, i);
			if (A > N) {
				break;
			}
			goal -= A;
			for (int j = i + ((9 - i) >> 1); j < 9; j++) {
				B = ToInteger(i, j);
				C = ToInteger(j, 9);
				if (B == C*goal) {
					cnt++;
				}else if (C*goal < B) {
					break;
				}
			}
		}
		return cnt;
	}
	int ans = 0;
	for (int i = idx; i < 9; i++) {
		swap(val[i], val[idx]);
		ans += DFS(idx + 1);
		swap(val[i], val[idx]);
	}
	return ans;
}

int main() {
	for (int i = 0; i < 9; i++) {
		val[i] = i + 1;
	}
	cin >> N;
	cout << DFS(0) << endl;
	return 0;
}

標題:剪格子

    如圖p1.jpg所示,3 x 3 的格子中填寫了一些整數。

    我們沿着圖中的紅色線剪開,得到兩個部分,每個部分的數字和都是60。

    本題的要求就是請你編程判定:對給定的m x n 的格子中的整數,是否可以分割爲兩個部分,使得這兩個區域的數字和相等。
    如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。   
    如果無法分割,則輸出 0

程序輸入輸出格式要求:

程序先讀入兩個整數 m n 用空格分割 (m,n<10)
表示表格的寬度和高度
接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000
程序輸出:在所有解中,包含左上角的分割區可能包含的最小的格子數目。


例如:
用戶輸入:
3 3
10 1 52
20 30 1
1 2 3

則程序輸出:
3

再例如:
用戶輸入:
4 3
1 1 1 1
1 30 80 2
1 1 1 100

則程序輸出:
10

(參見p2.jpg)


資源約定:
峯值內存消耗 < 64M
CPU消耗  < 5000ms


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

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

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

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

圖的深搜+剪枝

#include <bits/stdc++.h>

using namespace std;
const int maxn = (int)1e1+5;
const int INF = 0x3f3f3f3f;
typedef long long LL;

int img[maxn][maxn],vis[maxn][maxn],n,m,res;
int nxt[4][2] = {0,1,1,0,0,-1,-1,0};
LL goal;

void DFS (int x, int y, int cnt, LL sum) {
	if (sum > goal) {
		return ;
	}
	if (sum == goal) {
		res = min(res, cnt);
		return ;
	}
	int nx,ny;
	for (int i = 0; i < 4; i++) {
		nx = x + nxt[i][0];
		ny = y + nxt[i][1];
		if (nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny] == 1) {
			continue;
		}
		vis[nx][ny] = 1;
		DFS (nx, ny, cnt + 1, sum + img[nx][ny]);
		vis[nx][ny] = 0;
	}
}

int main() {
	goal = 0;
	cin >> m >> n;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> img[i][j];
			goal += img[i][j];
		}
	}
	if (goal % 2 ==0 && goal/2 > img[1][1]) {
		goal /= 2;
		res = INF;
		memset(vis, 0, sizeof(vis));
		vis[1][1] = 1;
		DFS(1, 1, 1, img[1][1]);
		if (res != INF) {
			cout << res << endl;
		}else {
			cout << 0 << endl;
		}
	}else {
		cout << 0 << endl;
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章