这两天自学了一线算法导论里分治策略的内容,秉着只有真正投入投入编程,才能更好的理解一种算法的思想的想法,兴致勃勃地找一些入门的题来学习。
搜了一下最后把目光锁定在了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)】
合并:
以递归的方式合并不断分解问题,局部解决以后又返回上一个状态。
注:因为其他部分为空,所以图形以外的数组部分要填' '
具体实现
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]='