這兩天自學了一線算法導論里分治策略的內容,秉着只有真正投入投入編程,才能更好的理解一種算法的思想的想法,興致勃勃地找一些入門的題來學習。
搜了一下最后把目光鎖定在了Poj fractal這一個題上。以前一直對這種題無從下手,通過對這一條題的分析與理解,算是第一次對分治思想有一個較為具象的了解。
分治思想的依托為遞歸。
下面我嘗試用分支策略的思想描述這一題。
分解:
在這條題里,通過分析題目可以知道:每一個更大一點的圖形都是由前一個狀態的小圖形放置在對應位置組成的;而每一個小圖形的又由更前一個狀態的圖形組成。
因此,我們可以把一開始輸入的規模m視為【大問題】,大問題的內容是:如何按照‘X'的形態填充對應位置的字符。
接着,把大問題划分為5個規模為m-1視為【大問題的划分問題1】,問題1 的內容是:如何按照‘X'的形態填充對應位置的字符。
再接着,把問題1的內容划分為更小的5個規模為m-2的【問題1的划分問題2】,問題2 的內容是:如何按照‘X'的形態填充對應位置的字符。
……
終態:當問題被划分為為規模為1 的子問題時,已經不那么再繼續划分了。這時候可以直接在當前位置上填一個“X"。
將每一個層次的問題視為一個狀態, 相鄰狀態的關系為【當前問題規模數=前一個問題規模數-1】
解決:
通過觀察每一個規模的圖形不難發現其中的規律
XXXOOOXXX
XXXOOOXXX
XXXOOOXXX
OOOXXXOOO
OOOXXXOOO
OOOXXXOOO
XXXOOOXXX
XXXOOOXXX
XXXOOOXXX
每一個圖形的規模面積為m*m,長與寬正好是規模數m,在左上、右上、中部、左下、右下分別為前一個規模的圖形,其他部分為空
而每一個規模為m的圖形,某一個部分離相鄰一個部分的距離為3^(m-2)【比如左上部分第一個格子的位置距離右上部分第一個格子的距離:縱坐標相同,橫坐標為+3^(m-2)】
合並:
以遞歸的方式合並不斷分解問題,局部解決以后又返回上一個狀態。
注:因為其他部分為空,所以圖形以外的數組部分要填'\0'
具體實現
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 char a[1000][1000]; 7 void dfs(int cur,int x,int y) 8 { 9 if(cur==1) 10 { 11 a[x][y]='X'; 12 return ; 13 } 14 int s=(int)pow(3.0,cur-2); 15 //分別打印左上、右上、中間、左下、右下x應該變為的圖形 16 dfs(cur-1,x,y); 17 dfs(cur-1,x,y+2*s); 18 dfs(cur-1,x+s,y+s); 19 dfs(cur-1,x+2*s,y); 20 dfs(cur-1,x+2*s,y+2*s); 21 } 22 int main() 23 { 24 int n; 25 while(~scanf("%d",&n)) 26 { 27 if(n==-1) break; 28 memset(a,' ',sizeof(a)); 29 dfs(n,1,1); 30 int s=(int)pow(3.0,n-1); 31 for(int i=1;i<=s;i++) 32 { 33 a[i][s+1]='\0';//3的n-1次方后面沒有多余空格 34 35 } 36 for(int i=1;i<=s;i++) 37 { 38 printf("%s\n",a[i]+1); 39 } 40 printf("-\n"); 41 } 42 return 0; 43 }
詳解代碼