分形 打印

分形 ,每一部分都(至少近似地)是整体缩小后的形状。

分形,具有以非整数维形式充填空间的形态特征???

通常被定义为“一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”,即具有自相似的性质

正是由于每一部分都(至少近似地)是整体缩小后的形状这个性质,可以通过递归来打印分形
对于n阶图形,由若干n-1阶分形构成,为了打印n阶图形,先找到 n阶图形整体中的一点,到各个分形中对应点 之间的距离、方位,从而递归打印出各个分形。
以下几题,所谓的 “从左上角开始扩散递归” 和 “从中心开始扩散递归” ,就是找到整体的点和各分形中对应位置的点
譬如 确定了n阶图形的点在左上角,接着就找各分形中左上角的点 的方位
由于打印图形靠的是输出矩阵,因此确定图形的点只要在 该图形所处的矩阵之内即可,该点不一定要有图案

【1】1104: 分形图

http://oj.ecustacm.cn/problem.php?id=1104

从左上角扩散递归

由于从左上角扩散递归,左上角图形和右上、中间、左下、右下都是上一阶图形,
且左上、中间 图形之间间距是上一阶图形的尺寸
左上、左下/右上 图形之间间距是(2*上一阶图形的尺寸)
注意对应矩阵的坐标系,行递增的方向(竖直向下)对应x轴

每一阶的图形尺寸都是 方形,看图片有点看不出来,但题干已经明确指出了

#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
typedef long long ll;
ll power(int base,int expon){
	ll res=1;
	while(expon){
		if(expon&1)res*=base;
		base*=base;
		expon>>=1;
	}
	return res;
}
char map[800][800]={};//power(3,6)=729
void draw(int n,int x,int y){
	if(n==1){
		map[x][y]='X';
		return ;//递归要有结束的临界条件 
	}
	else{
		int interval=power(3,n-2);//上一阶图形的尺寸 
	//由于从左上角扩散递归,左上角图形和右上、中间、左下、右下都是
//	上一阶图形,且左上、中间 图形之间间距是上一阶图形的尺寸
//	左上、左下/右上 图形之间间距是(2*上一阶图形的尺寸)
//注意对应矩阵的坐标系,行递增的方向(竖直向下)对应x轴 
		 draw(n-1,x,y);//左上角是上一阶的图形
		 draw(n-1,x,y+2*interval);//右上 
		 draw(n-1,x+interval,y+interval);//中 
		 draw(n-1,x+2*interval,y);// 左下 
		 draw(n-1,x+2*interval,y+2*interval);//右下 
	}
}
int main(int argc, char** argv) {
	 int n;
	 cin>>n;
	 int size=power(3,n-1);
	 for(int i=1;i<=size;i++){
	 	for(int j=1;j<=size;j++){
	 		map[i][j]=' ';
		 }
	 }//n对应的尺寸是size这个方框,因此这个方框中的空格也要输出	
	 draw(n,1,1);//从左上角开始扩散递归
	for(int i=1;i<=size;i++){
	 	for(int j=1;j<=size;j++){
	 		cout<<map[i][j];
		 }
		 cout<<endl; 
	 }
	return 0;
}

从中心扩散递归

参考博客
在这里插入图片描述

#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
typedef long long ll;
ll power(int base,int expon){
	ll res=1;
	while(expon){
		if(expon&1)res*=base;
		base*=base;
		expon>>=1;
	}
	return res;
}
char map[800][800]={};//power(3,6)=729
void draw(int n,int x,int y){
	if(n==1){
		map[x][y]='X';
		return ;//递归要有结束的临界条件 
	}
	else{
		int interval=power(3,n-2);//上一阶图形的尺寸 
//中心 到 四个角的中心 的距离都是 上一阶图形的尺寸
		 draw(n-1,x,y);//中心是上一阶的图形
		 draw(n-1,x-interval,y+interval);//右上 
		 draw(n-1,x-interval,y-interval);//左上
		 draw(n-1,x+interval,y-interval);// 左下 
		 draw(n-1,x+interval,y+interval);//右下 
	}
}
int main(int argc, char** argv) {
	 int n;
	 cin>>n;
	 int size=power(3,n-1);	
	 draw(n,400,400);
	 //从最中心开始扩散递归,输出时根据尺寸确定图形所在的边界方框 
	for(int i=400-size/2;i<=400+size/2;i++){
	 	for(int j=400-size/2;j<=400+size/2;j++){
	 		if(map[i][j]=='X')cout<<map[i][j];
	 		else cout<<" ";
		 }
		 cout<<endl; 
	 }
	return 0;
}

【2】 打印图形(2018年第9届蓝桥杯省赛试题)。(原题是填空题)

编写一个程序,在控制台绘制分形图(就是整体与局部自相似的图形)。

当n=1,2,3的时候,输出如下:

在这里插入图片描述

(1)从左上角扩散递归,左上角不用打印,递归到有图形的各个位置就好

  度数为n的图形,其大小是3n*3n,可以用字符数组来存储图形中各个字符。

  度数为n的图形可以有以下递归式子表示:

                     B(n - 1)       

       B(n - 1)  B(n - 1)   B(n - 1)  

                     B(n - 1)

  设递归函数void draw(int n,int x,int y)表示在(x,y)
  位置开始设置度数为n的图形,它由5个度数为n-1的图形组成,
  其起始位置分别为:(x+s,y)、(x,y+s)、(x+s,y+s)
  、(x+2*s,y+s)和(x+s,y+2*s),其中s=3^(n-1)。
#include <iostream>

using namespace std;

#define N 729

void draw(char a[][N], int n, int row, int col)

{

     if(n==0){

            a[row][col] = 'O';

            return;

     }

     int w = 1;

     int i;

     for(i=1; i<=n-1; i++) w *= 3;

     draw(a,n-1, row+w, col);

     draw(a,n-1, row, col+w);

     draw(a,n-1, row+w,col+w);

     draw(a,n-1, row+2*w, col+w);

     draw(a,n-1, row+w,col+2*w);

      }

int main()

{

     char a[N][N];

     int n,w,i,j;

     for(i=0;i<N;i++)

       for(j=0;j<N;j++)

            a[i][j] = ' ';

     cin>>n;

     w=1;

     for(i=1; i<=n; i++) w *= 3;

     draw(a,n,0,0);

     for(i=0; i<w; i++)

     {

            for(j=0; j<w; j++)

                   cout<<a[i][j];

            cout<<endl;

     }

     return 0;

}

(2)从中心扩散递归

要注意尺寸噢,上一题 n阶的尺寸时3^n-1
这题 n阶的尺寸时3^n
到左边、右边和到左上、左下距离不一样,但每个距离单位都是上一阶的尺寸(上一题 n阶的尺寸时3 ^ n-2
这题 n阶的尺寸时3 ^ n-1
由于还是上下左右中心 围绕中心,可以从中心出发

#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
typedef long long ll;
ll power(int base,int expon){
	ll res=1;
	while(expon){
		if(expon&1)res*=base;
		base*=base;
		expon>>=1;
	}
	return res;
}
char map[800][800]={};//power(3,6)=729
void draw(int n,int x,int y){
	if(n==0){
		map[x][y]='O';
		return ;//递归要有结束的临界条件 
		
	}
	else{
		int interval=power(3,n-1);//上一阶图形的尺寸 
//中心 到 四个角的中心 的距离都是 上一阶图形的尺寸
		 draw(n-1,x,y);//中心是上一阶的图形
		 draw(n-1,x,y-interval);//左 
		 draw(n-1,x,y+interval);//右
		 draw(n-1,x-interval,y);//上 
		 draw(n-1,x+interval,y);//下 
	}
}
//还是上下左右中的结构,每一阶的图形尺寸依旧是 方形 
int main(int argc, char** argv) {
	 int n;
	 cin>>n;
	 int size=power(3,n);	
	 draw(n,400,400);
 //从最中心开始扩散递归,输出时根据尺寸确定图形所在的边界方框 
	for(int i=400-size/2;i<=400+size/2;i++){
	 	for(int j=400-size/2;j<=400+size/2;j++){
	 		if(map[i][j]=='O')cout<<map[i][j];
	 		else cout<<" ";
		 }
		 cout<<endl; 
	 }
	return 0;
}

蓝桥杯填空题给出的源代码就是从中心扩散递归的思路

数组表现形式不同罢了,把数组和尺寸都当参数传进递归函数

3)蓝桥杯填空题给出的源程序。(请自己阅读体会)

#include <stdio.h>
#include <stdlib.h>
void show(char* buf, int w)
{
    int i,j;
    for(i=0; i<w; i++)  {

         for(j=0; j<w; j++)   {

              printf("%c", buf[i*w+j]==0? ' ' : 'o');
         }
         printf(" ");
    }
}
void draw(char* buf, int w, int x, int y, int size){
     if(size==1){
           buf[y*w+x] = 1;
           return;
      }
      int n = **size/3** ;       // 填空         
      draw(buf, w, x, y, n);
      draw(buf, w, x-n, y ,n);
      draw(buf, w, x+n, y ,n);
      draw(buf, w, x, y-n ,n);
      draw(buf, w, x, y+n ,n);
}
int main()
{
     int N = 3;
     int t = 1;
     int i;
     for(i=0; i<N; i++) t *= 3;
     char* buf = (char*)malloc(t*t);
     for(i=0; i<t*t; i++) buf[i] = 0;
     draw(buf, t, t/2, t/2, t);
     show(buf, t);
     free(buf);
     return 0;
}

【3】打印图形(2014年第5届蓝桥杯省赛试题)

在这里插入图片描述
编写一个程序,实现该图形的打印。
(1)编程思路。(来自链接)

度数n为4的图案在二维数组中的存储情况如图3所示。由图3可知,度数为4的图案可以由3个度数为3的图案(图3中分别用绿色、浅绿色和黄色蓝色底纹所示)。

在这里插入图片描述

因此,度数为n的图形G(n)可以由以下递归式子表示:

                      G(n - 1)       

              G(n - 1)      G(n - 1)

  设递归函数void draw(int n,int x,int y)表示在(x,y)
  位置开始设置度数为n的图形,它由3个度数为n-1的图形组成,
  其起始位置分别为:(x,y+2n-2)、(x+2n-2,y)和
  (x+2n-2,y+2n-1)。

  该递归函数的结束条件是:当n=1时(即度数为1的图形),
  只需在(x,y)位置设置一个字符'*'即可。
#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
typedef long long ll;
const int N=100;//这题要求打印4度的不过16 
ll power(int base,int expon){
	ll res=1;
	while(expon){
		if(expon&1)res*=base;
		base*=base;
		expon>>=1;
	}
	return res;
}
char map[100][100]={};//power(2,6)=64
void draw(int n,int x,int y){
	if(n==1){
		map[x][y]='*';
		return ;//递归要有结束的临界条件 
	}
	else{
		int interval=power(2,n-2);//上一阶图形的尺寸 
//中心 到 四个角的中心 的距离都是 上一阶图形的尺寸
//		 draw(n-1,x,y);//找的左上角这点是不绘制图案的 
		 draw(n-1,x,y+interval);//上 
		 draw(n-1,x+interval,y);//左下 
		 draw(n-1,x+interval,y+2*interval);//右下 
	}
}
//上、左下、右下的结构,每一阶的图形尺寸 宽高不同 
int main(int argc, char** argv) {
	 int n;
	 cin>>n;
	 int size=power(2,n-1);	
  	for(int i=0;i<N;i++)
       for(int j=0;j<N;j++) 
	   map[i][j] = ' ';
	draw(n,1,1);//从(0,0)还是(1,1)没关系,反正都是加上间距 
 //从左上角的点开始扩散递归,输出时根据尺寸确定图形所在的边界方框 
// 高尺寸是size,宽尺寸 size*2-1
	for(int i=1;i<=size;i++){
	 	for(int j=1;j<=size*2;j++){
	 		cout<<map[i][j]; 
		 }
		 cout<<endl; 
	 }
	return 0;
}

【4】谢尔宾斯基地毯(有点难,更能体现递归意义,尽量观察分形简单到只有一个字符的,更易观察出规律)

题目来源
Problem Description

谢尔宾斯基地毯是一种分形图案,它的定义如下:
令F(n)表示嵌套n层的谢尔宾斯基地毯,那么(下面的“空”均表示空格,仅为示意,实际输出时应仍为空格)

一般地,如果F(n-1)表示嵌套n-1层的谢尔宾斯基地毯,则F(n)的递归定义如下:

F(n-1)F(n-1)F(n-1)F(n-1)X(n-1)F(n-1)F(n-1)F(n-1)F(n-1)
其中X(n)表示边长为n的正方形,其内部被字符X完全填充。 现在输入一个正整数n,请画出嵌套n层的谢尔宾斯基地毯F(n)。

中心扩散递归
因为图形是中心对称的,外面的图形是分形,若干个分形包裹着一个正方形9*9,是奇数,有中心。(不要被图片迷惑,自己数一数正方形的行和列

这里找的固定点就是 每个图形中心正方形的中心,到分形正方形中心的距离、方位,至于中心正方形的打印
在这里插入图片描述

#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
typedef long long ll;
const int N=800;
ll power(int base,int expon){
	ll res=1;
	while(expon){
		if(expon&1)res*=base;
		base*=base;
		expon>>=1;
	}
	return res;
}
char map[800][800]={};
int dx[9]={-1,1,0,0,-1,1,-1,1,0};
int dy[9]={0,0,-1,1,-1,-1,1,1,0}; 
void draw(int n,int x,int y){
	if(n==1)return ;
	else if(n==2){
		map[x][y]='X';
		return ;//递归要有结束的临界条件 
	}
	else{
		int dis1=power(3,n-2);//上一阶图形的尺寸 
//中心 到 四周八个分形的中心 的横竖距离都是 上一阶图形的尺寸
//中心是有图案的,那么对中心也要递归 
		for(int i=0;i<9;i++){
			int cx=x+dx[i]*dis1;
			int cy=y+dy[i]*dis1;
			draw(n-1,cx,cy);
		} 
		int dis2=power(3,n-3);
//打印中间的正方形,观察n=3情形,每个分形都只是*,中间正方形其实是 
//中心点八方距离为dis2 的8个点,也就是8个距离为dis2的分形,和距离为
//dis1的分形意义是一样的,并不能视作正方形意义上来打印
//随着n增大,分形增大,只是由于dis2距离的限制,中心点距离dis2的8个分形
//会有重叠,恰好控制在一个正方形内 
		for(int i=0;i<9;i++){
			int cx=x+dx[i]*dis2;
			int cy=y+dy[i]*dis2;
			draw(n-1,cx,cy);
		} 
	}
}
int main(int argc, char** argv) {
	 int n;
	 cin>>n;
	 int size=power(3,n-1);	
	draw(n,400,400);
	for(int i=400-size/2-1;i<=400+size/2+1;i++){
	 	for(int j=400-size/2-1;j<=400+size/2+1;j++){
	 		if(i==400-size/2-1||i==400+size/2+1||j==400-size/2-1||j==400+size/2+1)cout<<'+';
	 		else if(map[i][j]=='X')cout<<'X';
			else cout<<" "; 
		 }
		 cout<<endl; 
	 }
	return 0;
}

【5】递归三角形图案(简单)。

  输入一个正整数n(n<=7),按图1的示例输出相应的由星号
  组成的三角形图案。

在这里插入图片描述

#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
typedef long long ll;
const int N=100;//这题要求打印7度的不过64 
ll power(int base,int expon){
	ll res=1;
	while(expon){
		if(expon&1)res*=base;
		base*=base;
		expon>>=1;
	}
	return res;
}
char map[100][100]={};//power(2,6)=64
void draw(int n,int x,int y){
	if(n==1){
		map[x][y]='*';
		return ;//递归要有结束的临界条件 
	}
	else{
		int interval=power(2,n-2);//上一阶图形的尺寸 
//中心 到 四个角的中心 的距离都是 上一阶图形的尺寸
		 draw(n-1,x,y);//左上
		 draw(n-1,x,y+interval);//右 
		 draw(n-1,x+interval,y);//左下 
	}
}
int main(int argc, char** argv) {
	 int n;
	 cin>>n;
	 int size=power(2,n-1);	
  	for(int i=0;i<N;i++)
       for(int j=0;j<N;j++) 
	   map[i][j] = ' ';
	draw(n,1,1);//从(0,0)还是(1,1)没关系,反正都是加上间距 
 //从左上角的点开始扩散递归,输出时根据尺寸确定图形所在的边界方框 
// 高尺寸是size,宽尺寸 size
	for(int i=1;i<=size;i++){
	 	for(int j=1;j<=size;j++){
	 		cout<<map[i][j]<<" "; 
		 }
		 cout<<endl; 
	 }
	return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值