2013藍橋杯題解c組C++
01 猜年齡
題目描述:
美國數學家維納(N.Wiener)智力早熟,11歲就上了大學。他曾在1935~1936年應邀來中國清華大學講學。
一次,他參加某個重要會議,年輕的臉孔引人注目。於是有人詢問他的年齡,他回答說:
“我年齡的立方是個4位數。我年齡的4次方是個6位數。這10個數字正好包含了從0到9這10個數字,每個都恰好出現1次。”
請你推算一下,他當時到底有多年輕。
解題思路:
根據題意選取可能的年齡範圍(可選取[10, 100]),使用一層迴圈一次列舉,找到符合要求的解即可。注意對數位的分離、位數判定、排序等操作
程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int i,j;
int n1,n2; //n1.n2分別儲存i^3與i^4
int digit[10],len; //digit儲存n1.n2中的各數位 len記錄位數
int suc; //suc標記i是否符合要求
for(i=10;i<=100;i++) //列舉年齡i
{
n1=i*i*i;
n2=i*i*i*i;
len=0;
while(n1)
{
digit[len++]=n1%10;
n1/=10;
}
if(len==4) //n1是4位數,繼續
{
while(n2)
{
digit[len++]=n2%10;
n2/=10;
}
if(len==10) //n2是6位數,繼續
{
sort(digit,digit+len); //0,1,2,...,9
suc=1;
for(j=0;j<len;j++)
{
if(digit[j]!=j)
{
suc=0;
break;
}
}
if(suc==1) //符合要求,輸出
printf("%d %d %d\n",i,i*i*i,i*i*i*i);
}
}
}
return 0;
}
執行結果:
18 5832 104976
答案:
18
02 馬虎的算式
題目描述:
小明是個急性子,上小學的時候經常把老師寫在黑板上的題目抄錯了。
有一次,老師出的題目是: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 這樣的算式一共有多少種呢?
請你利用計算機的優勢尋找所有的可能,並回答不同算式的種類數。
滿足乘法交換律的算式計為不同的種類,所以答案肯定是個偶數。
答案直接通過瀏覽器提交。
注意:只提交一個表示最終統計種類數的數字,不要提交解答過程或其它多餘的內容。
程式碼:
#include <stdio.h>
int main()
{
int a,b,c,d,e,n;
n=0;
for (a=1;a<10;a++)
for (b=1;b<10;b++)
{
if (a==b) continue;
else
for (c=1;c<10;c++)
{
if((c==a)||(c==b)) continue;
else
for (d=1;d<10;d++)
{
if((d==a) || (d==b) || (d==c)) continue ;
else
for (e=1;e<10;e++)
{
if ((e==a)||(e==b)||(e==c)||(e==d)) continue;
else if ( (10*a+b)*(100*c+10*d+e)==(100*a+10*d+b)*(10*c+e))
n++;
}
}
}
}
printf("%d\n",n);
return 0;
}
執行結果:
142
03 振興中華
題目描述
小明參加了學校的趣味運動會,其中的一個專案是:跳格子。
地上畫著一些格子,每個格子裡寫一個字,如下所示:
從我做起振
我做起振興
做起振興中
起振興中華
比賽時,先站在左上角的寫著“從”字的格子裡,可以橫向或縱向跳到相鄰的格子裡,但不能跳到對角的格子或其它位置。一直要跳到“華”字結束。
要求跳過的路線剛好構成“從我做起振興中華”這句話。
請你幫助小明算一算他一共有多少種可能的跳躍路線呢?
答案是一個整數,請通過瀏覽器直接提交該數字。
注意:不要提交解答過程,或其它輔助說明類的內容。
解題思路:
把每個格子都換成一個數字,從0算起,這樣,題目就變成了從0格跳到第7格的路線數目
程式碼:
#include <stdio.h>
int a[4][5];
int sum;
void dfs(int row,int col,int index)
{
//if(a[row][col]!=index) 這兩句話其實沒必要,感謝 hzylmf 提的意見
// return ;
if(a[row][col]==index && index==7)
sum++;
else {
if(row+1<4)
dfs(row+1,col,index+1);
if(col+1<5)
dfs(row,col+1,index+1);
}
}
int main()
{
int row,col;
for(row=0;row<4;row++)
for(col=0;col<5;col++)
a[row][col]=row+col;
dfs(0,0,0);
printf("sum = %d\n",sum);
return 0;
}
執行結果:
35
04 幻方填空
題目描述:
幻方是把一些數字填寫在方陣中,使得行、列、兩條對角線的數字之和都相等。
歐洲最著名的幻方是德國數學家、畫家迪勒創作的版畫《憂鬱》中給出的一個4階幻方。
他把1,2,3,…16 這16個數字填寫在4 x 4的方格中。
如圖所示,即:
16 ? ? 13
? ? 11 ?
9 ? ? *
? 15 ? 1
表中有些數字已經顯露出來,還有些用?和*代替。
請你計算出? 和 * 所代表的數字。並把 * 所代表的數字作為本題答案提交。
答案是一個整數,請通過瀏覽器直接提交該數字。
注意:不要提交解答過程,或其它輔助說明類的內容。
解題思路:
搜尋(dfs)+剪枝
可以使用一個二維陣列儲存該幻方(預先沒有填數的位置(包括?和*)為0),然後從第一個“0”開始(位置(0, 1))搜尋,依次試探2~16 15個數(因為1已經預先填入幻方)。找到符合要求的解。注意標記及剪枝(這裡使用了行剪枝,當搜尋到第二行時,用flag記錄第一行4個數的和,後面若發現某行4個數之和不等於flag,則該方案不符合要求),以提高程式效率。
程式碼:
#include <stdio.h>
#include <string.h>
#define maxn 20
int mat[4][4]={ //4*4幻方(0代表?或*)
{16,0,0,13},
{0,0,11,0},
{9,0,0,0},
{0,15,0,1}
};
int used[maxn]; //16個數的使用標記 1-已使用 0-未使用
int flag; //記錄第一行4個數之和
int Judge(int mt[][4]) //判斷各列與兩條對角線之和是否與各行之和相等
{
int i,j;
int sumc,sumln1,sumln2;
//依次計算各列4個數之和
for(j=0;j<4;j++)
{
sumc=0;
for(i=0;i<4;i++)
sumc+=mt[i][j];
//若sumc不等於flag,則方案不成立
if(sumc!=flag)
return 0;
}
//計算兩條對角線上4個數之和
sumln1=sumln2=0;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
//主對角線
if(i==j)
sumln1+=mt[i][j];
//副對角線
if(i==4-j-1)
sumln2+=mt[i][j];
}
}
//若sumln1或sumln2不等於flag,則方案不成立
if(sumln1!=flag || sumln2!=flag)
return 0;
//否則方案成立
return 1;
}
void dfs(int x,int y,int cursumr)
{
int i,j,num;
//搜尋終點
if(x==3 && y==4)
{
if(Judge(mat))
{
for(i=0;i<4;i++)
{
for(j=0;j<3;j++)
printf("%d ",mat[i][j]);
printf("%d\n",mat[i][3]);
}
}
return;
}
//一行搜尋結束:繼續搜尋下一行
if(y==4)
dfs(x+1,0,0);
//(x,y)已填入數字,則繼續搜尋下一位置(x,y+1)
if(mat[x][y]!=0)
dfs(x,y+1,cursumr+mat[x][y]);
//計算第一行4個數之和,並以此作為後續判斷的標記
if(x==1 && y==0)
{
flag=0;
for(j=0;j<4;j++)
flag+=mat[0][j];
}
//依次試探2-16 15個數
for(num=2;num<=16;num++)
{
//當前位置(x,y)沒有填數,並且num未使用
if(mat[x][y]==0 && !used[num])
{
//行剪枝:搜尋到每行最後一個數時,若發現cursumr+待填數num不等於flag
//則num無法填入,應試探下一個數num+1
if(x>=1 && y==3 && cursumr+num!=flag)
continue;
//填入
used[num]=1;
mat[x][y]=num;
//搜尋下一位置
dfs(x,y+1,cursumr+mat[x][y]);
//回溯
used[num]=0;
mat[x][y]=0;
}
}
}
int main()
{
//初始化
memset(used,0,sizeof(used));
//1.9.11.13.15.16已填入幻方,因此置used標記1
used[1]=1,used[9]=1,used[11]=1;
used[13]=1,used[15]=1,used[16]=1;
//從第一個問號(0,1)處開始搜尋
dfs(0,1,16);
return 0;
}
執行結果:
16 3 2 13
5 10 11 8
9 6 7 12
4 15 14 1
答案:
12
05 公約數公倍數
題目描述:
我們經常會用到求兩個整數的最大公約數和最小公倍數的功能。
下面的程式給出了一種演算法。
函式 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", ____________________________________); // 最小公倍數
}
請分析程式碼邏輯,並推測劃線處的程式碼,通過網頁提交。
注意:僅把缺少的程式碼作為答案,千萬不要填寫多餘的程式碼、符號或說明文字!!
解題思路:
最大公約數gcd與最小公倍數lcm 使用輾轉相除法求解,需要注意第一個數a比第二個數b時才可使用此法(因此當a>b時進行預處理,交換兩數)。
答案:
(m*n)/b
除錯程式碼:
#include <stdio.h>
// 交換數值
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",(m*n)/b); // 最小公倍數
}
int main()
{
int n1,n2;
scanf("%d %d",&n1,&n2);
myfunc(n1,n2);
return 0;
}
06 三部排序
題目描述:
一般的排序有許多經典演算法,如快速排序、希爾排序等。
但實際應用時,經常會或多或少有一些特殊的要求。我們沒必要套用那些經典演算法,可以根據實際情況建立更好的解法。
比如,對一個整型陣列中的數字進行分類排序:
使得負數都靠左端,正數都靠右端,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
請分析程式碼邏輯,並推測劃線處的程式碼,通過網頁提交
注意:僅把缺少的程式碼作為答案,千萬不要填寫多餘的程式碼、符號或說明文字!!
解題思路:
排序演算法的改進實現
基本思想:陣列中的0將整個陣列分成3部分,所有小於0的數放到0的前面,所有大於0的數放到0的後面。遇到0的時候,忽略之,繼續處理下一個數。由於這裡的left指標不動,還是指向0的前一個負數,所以碰到小於0的數的時候又會把前面忽略的0交換過來,這樣就會把所有0堆到後面來。最後跳過所有0,直到p>right結束。
答案:
p++
除錯程式碼:
#include <stdio.h>
#define maxn 1010
int n;
int a[maxn];
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{
p++; //填空位置
}
}
}
int main()
{
int i;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort3p(a,n);
for(i=0;i<n-1;i++)
printf("%d ",a[i]);
printf("%d\n",a[n-1]);
return 0;
}
07 核桃的數量
題目描述:
小張是軟體專案經理,他帶領3個開發組。工期緊,今天都在加班呢。為鼓舞士氣,小張打算給每個組發一袋核桃(據傳言能補腦)。他的要求是:
1. 各組的核桃數量必須相同
2. 各組內必須能平分核桃(當然是不能打碎的)
3. 儘量提供滿足1,2條件的最小數量(節約鬧革命嘛)
程式從標準輸入讀入:
a b c
a,b,c都是正整數,表示每個組正在加班的人數,用空格分開(a,b,c<30)
程式輸出:
一個正整數,表示每袋核桃的數量。
樣例輸入1:
2 4 5
樣例輸出1:
20
樣例輸入2:
3 1 1
樣例輸出2:
3
資源約定:
峰值記憶體消耗(含虛擬機器) < 64M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
解題思路: gcd&lcm問題
根據要求1. 2. -> 三個數的公倍數(滿足都能平分)
根據要求3. -> 三個數的最小公倍數(滿足"最小")
由此可確定題目模型:求a, b, c三個數的最小公倍數
求解時,首先求出a, b兩個數的最小公倍數temp,然後求temp, c兩個數的最小公倍數即可。這裡使用遞迴實現。
程式碼:
#include <stdio.h>
int gcd(int n1,int n2)
{
if(n2==0)
return n1;
return gcd(n2,n1%n2);
}
int lcm3(int a,int b,int c)
{
int temp=a*b/gcd(a,b);
return temp*c/gcd(temp,c);
}
int main()
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
printf("%d\n",lcm3(a,b,c));
return 0;
}
08 列印十字圖
題目描述:
小明為某機構設計了一個十字型的徽標(並非紅十字會啊),如下所示
對方同時也需要在電腦dos視窗中以字元的形式輸出該標誌,並能任意控制層數。
為了能準確比對空白的數量,程式要求對行中的空白以句點(.)代替。
輸入格式:
一個正整數 n (n<30) 表示要求列印圖形的層數
輸出格式:
對應包圍層數的該標誌。
樣例輸入1:
1
樣例輸出1:
..$$$$$..
..$...$..
$$$.$.$$$
$...$...$
$.$$$$$.$
$...$...$
$$$.$.$$$
..$...$..
..$$$$$..
樣例輸入2:
3
樣例輸出2:
..$$$$$$$$$$$$$..
..$...........$..
$$$.$$$$$$$$$.$$$
$...$.......$...$
$.$$$.$$$$$.$$$.$
$.$...$...$...$.$
$.$.$$$.$.$$$.$.$
$.$.$...$...$.$.$
$.$.$.$$$$$.$.$.$
$.$.$...$...$.$.$
$.$.$$$.$.$$$.$.$
$.$...$...$...$.$
$.$$$.$$$$$.$$$.$
$...$.......$...$
$$$.$$$$$$$$$.$$$
..$...........$..
..$$$$$$$$$$$$$..
請仔細觀察樣例,尤其要注意句點的數量和輸出位置。
資源約定:
峰值記憶體消耗 < 64M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
解題思路: 文字圖形問題
一般地,此類圖形都有一定的規律,通常有兩種主要解法:①遞迴 ②抓住規律(對稱性、週期性等是經常出現的),迴圈填圖。
這裡使用②即可,關鍵是圖形中的規律。
程式碼:
#include <stdio.h>
#include <string.h>
#define maxlen 130
int n;
char area[maxlen][maxlen];
int main()
{
int i,j;
int len,flag;
scanf("%d",&n);
//初始化標誌
memset(area,'.',sizeof(area));
//確定(正方形)區域長度
len=4*n+5;
//填充區域I
for(i=0;i<=len/2;i+=2)
for(j=i+2;j<=len/2;j++)
area[i][j]='$';
//填充區域II
for(j=0;j<=len/2;j+=2)
for(i=j+2;i<=len/2;i++)
area[i][j]='$';
//填充區域III
for(i=len/2,j=len/2;i>=2,j>=2;i-=2,j-=2)
{
area[i][j]='$';
area[i][j-1]='$';
area[i-1][j]='$';
}
//左右對稱
for(i=0;i<=len/2;i++)
for(j=1;j<=len/2;j++)
area[i][len/2+j]=area[i][len/2-j];
//上下對稱
for(i=1;i<=len/2;i++)
for(j=0;j<len;j++)
area[len/2+i][j]=area[len/2-i][j];
//輸出該標誌
for(i=0;i<len;i++)
{
for(j=0;j<len-1;j++)
printf("%c",area[i][j]);
printf("%c\n",area[i][len-1]);
}
return 0;
}
09 帶分數
題目描述:
100 可以表示為帶分數的形式:100 = 3 + 69258 / 714
還可以表示為:100 = 82 + 3546 / 197
注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。
類似這樣的帶分數,100 有 11 種表示法。
題目要求:
從標準輸入讀入一個正整數N (N<1000*1000)
程式輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。
注意:不要求輸出每個表示,只統計有多少表示法!
樣例輸入1:
100
樣例輸出1:
11
樣例輸入2:
105
樣例輸出2:
6
資源約定:
峰值記憶體消耗 < 64M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
題目描述:
列舉+全排列 / 搜尋(dfs)
根據題意可確定帶分數的基本形式:N= num1 + num2 / num3。
因此題目的關鍵即確定num1, num2, num3三個數。
又由於帶分數中1~9 9個數是隨機出現的,因此可通過全排列使9個數"隨機滾動",通過迴圈(或dfs),將全排列中的9個數分成3組,以確定num1,
num2與num3。當N= num1 + num2 / num3並且num2能整除num3時,才是符合要求的解。
為提高程式執行效率,可進行一定的優化。
程式碼:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int N;
int ans=0;
int a[9]={1,2,3,4,5,6,7,8,9};
int getDigit(int n) //獲取n的位數
{
int temp=n;
int len=0;
while(temp!=0)
{
len++;
temp/=10;
}
return len;
}
int main()
{
int i,j,k;
int num1,num2,num3;
int digit,result;
scanf("%d",&N);
digit=getDigit(N);
do
{
//使用i,j確定num1與num2 num2與num3的分界點
for(i=0;i<digit;i++)
{
for(j=i+1;j<8;j++)
{
num1=num2=num3=0;
for(k=0;k<=i;k++) //累加求num1
num1=num1*10+a[k];
if(num1>N) //優化點:當num1比N大時,即使num2/num3再小,也不符合要求,故這個解不合題意
continue;
for(k=i+1;k<=j;k++) //累加求num2
num2=num2*10+a[k];
for(k=j+1;k<9;k++) //累加求num3
num3=num3*10+a[k];
result=num1+num2/num3;
if(num2%num3==0 && result==N) //注意結果為N並且num2能整除num3時,才是我們需要的解
ans++;
}
}
} while(next_permutation(a,a+9));
printf("%d\n",ans);
return 0;
}
10 剪格子
題目描述:
如圖所示,3 x 3 的格子中填寫了一些整數
我們沿著圖中的紅色線剪開,得到兩個部分,每個部分的數字和都是60。
本題的要求就是請你程式設計判定:對給定的m x n 的格子中的整數,是否可以分割為兩個部分,使得這兩個區域的數字和相等。
如果存在多種解答,請輸出包含左上角格子的那個區域包含的格子的最小數目。
如果無法分割,則輸出 0
程式輸入輸出格式要求:
程式先讀入兩個整數 m n 用空格分割 (m,n<10)
表示表格的寬度和高度
接下來是n行,每行m個正整數,用空格分開。每個整數不大於10000
程式輸出:在所有解中,包含左上角的分割區可能包含的最小的格子數目。
樣例輸入1:
3 3
10 1 52
20 30 1
1 2 3
樣例輸出1:
3
樣例輸入2:
4 3
1 1 1 1
1 30 80 2
1 1 1 100
樣例輸出2:
10
(參見下圖)
資源約定:
峰值記憶體消耗 < 64M
CPU消耗 < 5000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。
提交時,注意選擇所期望的編譯器型別。
解題思路:
題意:從格子的左上角開始,沿上下左右4個方向,將n * m的格子分成兩部分,使兩部分的數字之和相等。
也就是說當發現當前搜尋的部分數字之和為格子數字總和的一半時,該組解符合題意。在所有符合題意的解中尋找最優解。
因為要尋找最優解,故可以根據問題情境進行"剪枝",以提高程式執行效率。以下關鍵點可供參考:
(1)預處理:輸入的同時求n*m格子區域中所有數字之和sum。若sum不是偶數,則一定不能分成符合要求的兩部分,無解;
(2)搜尋過程中,若發現當前格子數目超過了最優解,則繼續搜尋下去,即使能夠找到解,也一定不是最優解。因此不必繼續向後搜尋,可以另謀其他方案。
程式碼:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define maxm 15
#define maxn 15
#define INF pow(2,31)-1 //初始化minans
int m,n;
int sum=0,minans=INF; //sum-n*m區域中數字之和 minans-所求最優解
int map[maxn][maxm],vis[maxn][maxm]; //n*m區域
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; //4個搜尋方向
//從(x,y)開始搜尋,當前數字之和cursum,當前格子數ans
void dfs(int x,int y,int cursum,int ans)
{
int i,temp;
int newx,newy;
//剪枝:若發現當前格子數超過了最優解,則不再繼續搜尋該方案
if(ans>minans)
return;
//終點:找到符合要求的解
if(cursum==sum/2)
{
//更新minans
if(ans<minans)
minans=ans;
return;
}
//試探上下左右4個搜尋方向
for(i=0;i<4;i++)
{
newx=x+dir[i][0];
newy=y+dir[i][1];
//若新位置(newx,newy)不出界並且未走過
if(newx>=0 && newx<n && newy>=0 && newy<m && !vis[newx][newy])
{
//則從新位置開始繼續搜尋
vis[newx][newy]=1;
dfs(newx,newy,cursum+map[newx][newy],ans+1);
vis[newx][newy]=0;
}
}
}
int main()
{
int i,j;
scanf("%d %d",&m,&n);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&map[i][j]);
sum+=map[i][j];
}
}
//剪枝:區域數字之和為奇數,則無解
if(sum%2!=0)
printf("0\n");
//其它情況:從左上角格子(0,0)開始搜尋
else
{
memset(vis,0,sizeof(vis));
vis[0][0]=1;
dfs(0,0,map[0][0],1);
//若minans未更新,則無解
if(minans==INF)
printf("0\n");
//否則輸出最優解
else
printf("%d\n",minans);
}
return 0;
}
相關文章
- 2013藍橋杯題解c++A組C++
- 第十屆藍橋杯C++國賽B組部分題解(假題解)C++
- 【藍橋杯考前突擊】第十屆藍橋杯省賽C/C++大學B組 試題 D 數的分解C++
- 第十四屆藍橋杯省賽C++ B組(個人經歷 + 題解)C++
- 第四屆藍橋杯C/C++本科B組第二道大題C++
- 【每週例題】藍橋杯 C++ 多數C++
- 第十三屆藍橋杯省賽C/C++ B組C++
- 2017第八屆藍橋杯C/C++ B組省賽第二題 秒解C++
- 試題B:小球反彈(第十五屆藍橋杯省賽B組c/c++組)C++
- 2013年第四屆藍橋杯省賽試題及詳解(Java本科C組)Java
- 2016年藍橋杯C/C++組省賽第三題--湊算式C++
- 2016年藍橋杯C/C++組省賽第四題--快速排序C++排序
- 2020藍橋杯省賽B組C++(第二場)真題C++
- 【題目解析】藍橋杯23國賽C++中高階組 - 鬥魚養殖場C++
- 2016年藍橋杯C/C++組省賽第一題--煤球數目C++
- 2016年藍橋杯C/C++組省賽第二題--生日蠟燭C++
- 2013年藍橋杯JavaA組題4(顛倒的價牌)Java
- 2013第四屆藍橋杯省賽C++A組【第一題:高斯日記】C++
- 【每週例題】藍橋杯 C++ 雞哥的奇特密碼C++密碼
- 【每週例題】藍橋杯 C++ 雞哥的蛋糕大作戰C++
- 第十屆藍橋杯C語言大學B組C/C++ 試題F:特別的數C語言C++
- 2016年省賽第七屆藍橋杯B組C/C++第九題解 交換瓶子C++
- 藍橋杯真題
- C++實現 藍橋杯 k倍區間C++
- 第十五屆藍橋杯軟體賽省賽C/C++B 組題解C++
- 藍橋杯javaB組備賽Java
- 2019年省賽第十屆藍橋杯B組C/C++試題H解 等差數列C++
- 歷屆藍橋杯省賽(C、C++)的答案(轉)C++
- 【藍橋杯考前突擊】第十一屆藍橋杯校賽模擬C/C++ 正整數序列C++
- 藍橋杯__省賽__第七屆__C/C++__大學A組C++
- 藍橋杯__省賽__第八屆__C/C++__大學A組C++
- 藍橋杯__省賽__第九屆__C/C++__大學A組C++
- 第十五屆藍橋杯大賽軟體賽省賽 C/C++ 大學 A 組C++
- 藍橋杯-座次問題
- 藍橋杯-日期問題
- 2013第四屆藍橋杯省賽C++B組【第六題:三部排序】C++排序
- 藍橋杯模板(三)python組Python
- 藍橋杯模板(二)python組Python