藍橋杯之方格填數,寒假作業
問題描述:
方格填數
如下的10個格子
+--+--+--+
| | | |
+--+--+--+--+
| | | | |
+--+--+--+--+
| | | |
+--+--+--+
(如果顯示有問題,也可以參看下圖)
填入0~9的數字。要求:連續的兩個數字不能相鄰。
(左右、上下、對角都算相鄰)
一共有多少種可能的填數方案?
請填寫表示方案數目的整數。
注意:你提交的應該是一個整數,不要填寫任何多餘的內容或說明性文字。
首先,不必花心思考慮怎麼把這個圖形在程式中表現出來,一個一維陣列就可以搞定,我們這樣做:
自上而下,從左向右分別給這些單元格標記為 a[1],a[2],...,a[10]。
要做到題述要求,對於 a[1],只需要 a[1] 和 a[2],a[4],a[5],a[6] 之間的絕對值大於 1 即可。對其他位置亦是如此,如果填寫的不符合要求就回溯,和深搜的思想一樣,如果不是很理解深搜,請看這篇文章:
http://blog.csdn.net/eliminatedacmer/article/details/79334903
我們只需要將符合題意的結果找出來就可以了:
#include <iostream> #include <cmath> using namespace std; int count = 0; int a[12],b[12]; void Check() { if(abs(a[1]-a[2])>1 && abs(a[1]-a[4])>1 && abs(a[1]-a[5])>1 && abs(a[1]-a[6])>1 && abs(a[2]-a[3])>1 && abs(a[2]-a[5])>1 && abs(a[2]-a[6])>1 && abs(a[2]-a[7])>1 && abs(a[3]-a[6])>1 && abs(a[3]-a[7])>1 && abs(a[4]-a[5])>1 && abs(a[4]-a[8])>1 && abs(a[4]-a[9])>1 && abs(a[5]-a[6])>1 && abs(a[5]-a[8])>1 && abs(a[5]-a[9])>1 && abs(a[5]-a[10])>1 && abs(a[6]-a[7])>1 && abs(a[6]-a[9])>1 && abs(a[6]-a[10])>1 && abs(a[7]-a[10])>1 && abs(a[8]-a[9])>1 && abs(a[9]-a[10])>1) { count++; } } void Fill_numbers(int x) { if(x > 10) { Check(); return; } for(int i = 0;i<10;i++) { if(b[i] == 0) { b[i] = 1; a[x] = i; Fill_numbers(x+1); b[i] = 0; } } } int main() { Fill_numbers(1); cout<<count; return 0; }
接下來是寒假作業,請讀者體會這兩者思路上的差異。
問題描述:
寒假作業
現在小學的數學題目也不是那麼好玩的。
看看這個寒假作業:
□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □
(如果顯示不出來,可以參見下圖)
每個方塊代表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 <iostream>
#define _MAX 13
using namespace std;
int count = 0;
int num[_MAX];
int vis[_MAX];
void dfs(int n)
{
int i = 0;
if (n >= _MAX)
{
if (num[0] + num[1] == num[2] && num[3] - num[4] == num[5]&&num[6] * num[7] == num[8]&&num[10] * num[11] == num[9])
count++;
return ;
}
for (; i < _MAX; i++)
{
if (!vis[i])
{
vis[i] = 1;
num[n] = i + 1;
dfs(n + 1);
vis[i] = 0;
}
}
return ;
}
int main()
{
dfs(0);
cout<<count;
return 0;
}
這種做法當然是正確的,但是如果你運行了一遍就會知道,它要得出正確的結果,需要長達幾分鐘的執行時間,因為我們是在所有數都填好之後才開始進行判斷,而且這裡有12個空,13個數字,因此大大增加了計算量,因此,我們需要優化演算法,讓它不要進行多餘的計算,也就是說,如果第一個表示式都不滿足的情況下,以後所有後續的填數工作我們都不需要做了。即:
#include <iostream>
#define _MAX 13
using namespace std;
int count = 0;
int num[_MAX];
int vis[_MAX];
int Check(int n)
{
if (n == 2)
{
if (num[0] + num[1] == num[2])
{
return 1;
}
}
else if (n == 5)
{
if (num[3] - num[4] == num[5])
{
return 1;
}
}
else if (n == 8)
{
if (num[6] * num[7] == num[8])
{
return 1;
}
}
else if (n == 11)
{
if (num[10] * num[11] == num[9])
{
count++;
return 1;
}
}
else
{
return 1;
}
return 0;
}
void dfs(int n)
{
int i = 0;
if (n >= _MAX)
{
return ;
}
for (; i < _MAX; i++)
{
if (!vis[i])
{
vis[i] = 1;
num[n] = i + 1;
if (!Check(n))
{
vis[i] = 0;
continue;
}
dfs(n + 1);
vis[i] = 0;
}
}
return ;
}
int main()
{
dfs(0);
cout<<count;
return 0;
}