上文鏈接:藍橋杯真題之購物單(一分鐘巧解)
方格分割
6x6的方格,沿着格子的邊線剪開成兩部分。
要求這兩部分的形狀完全相同。
如下三圖就是可行的分割法。
試計算:
包括這3種分法在內,一共有多少種不同的分割方法。
注意:旋轉對稱的屬於同一種分割法。
我的思路
- 方格解析:該方格是7行7列的方格,紅橙兩連通方格圍繞(3,3)對稱。圖示如下。
- 思路:求解對稱的方式有多少種,可以利用DFS(深度遍歷)+遞歸思想,從中心對稱點開始走,一次走到結尾。過程爲:先標註當前點及對稱點,然後沿着當前點向四個方向走,走前判斷下步是否合法且是否已經走過,若合法,走到下步繼續重複此過程(遞歸實現)。直到走到邊界。注意點如下。
- 從該點走完整個路徑時回溯該點未走過的狀態,爲下次再走做準備。
- 因爲從對稱中心(3,3)向四個方向均可以走,如果開始沿着四個方向,比如向前一直走和向後一直走和向上一直帶走,向下一直走路徑相同,那麼最後結果旋轉之後呈現的對稱方式相同。所以最後得到的結果應該除以4。
算法展示
#include <iostream>
using namespace std;
typedef int It;//爲方便大範圍時修改進行類型定義
It tag[7][7];//標註被訪問的點
It dire[4][2]={{0,1},{0,-1},{-1,0},{1,0}};//定義行走方向,上下左右
It ans=0;//記錄結果,因爲(x,y)向四個方向走並標註對稱方格,旋轉之後沿四個方向走相同步驟其實是同一種對稱方式,所以結果應該除以4
It lenDire = sizeof(dire)/sizeof(dire[0]);//獲取方向長度
void dfs(It x,It y)//深度遍歷
{
if(x==0||y==0||x==6||y==6)//走到邊界,表示可以構成對稱方格,記錄該方式。
{
ans++;
return;
}
//標註走過點
tag[x][y]=1;
tag[6-x][6-y]=1;
//改變方向行走
for(int i =0;i<lenDire;i++)
{
int curX = x+dire[i][0];
int curY = y+dire[i][1];
//判斷當前走向是否合法且未走過
if(tag[curX][curY]==1||(curX<0||curY<0||curX>6||curY>6))continue;
dfs(curX,curY);
}
//查找完成後回溯標註點
tag[x][y]=0;
tag[6-x][6-y]=0;
}
int main()
{
dfs(3,3);
cout<<ans/4<<endl;
return 0;
}