心形打印999
农历七月初七,七夕节也就是中国民间版的所谓情人节,利用java打印心型999个图案可以让程序员更浪漫一些。现在下面由小编简要的说一下如何做到。
首先下面是打印心形但却不是999个的代码,然后在上面将其修改就好了。
注意:
1.爱心的公式 (x²+y²-1)³-x²*y³=0
2.x和y的取值范围[-1.5, 1.5]
原型代码:
/* 程序Ⅰ,程序可以在控制台打印由*号构成的心形图案。*/ public class HeartV1 { /* 爱心的公式 (x²+y²-1)³-x²*y³=0 */ public static void main(String[] args) { int cx = 0, cy = 0; // 问y 、 x 总共循环了多少次 float dx = 0.05f, dy = 0.1f; int stars=0;//计数器 for (float y = (float)1.5; y > -1.5; y -= dy, cy++){ cx = 0; for (float x = (float) -1.5; x < 1.5; x += dx, cx++){ float a = x * x + y * y - 1; if ((a * a * a - x * x * y * y * y) <= 0.0){ System.out.print("*");// 心形区域内打印* stars++; } else{ System.out.print(" "); // 心形区域外打印空格 } } System.out.println(""); // 本行结束,换行准备下一行的输出 } System.out.printf("cx=%d, cy=%d%n", cx, cy); System.out.printf("count=%d", stars); } }
该程序可以正常执行得到的输出结果如下:
cx=61, cy=30
stars=736
最后一行输出的cx和cy表示y循环(最外层循环)次数是30次;cx表示每次外循环需要执行的x循环(内层循环)次数是61次。
于是利用java打印心型999个*图案总体思想就是调整原版程序x和y的循环次数,其它参数保持不变,比如x和y的取值范围[-1.5, 1.5]不变,即调整dx或/和dy。
△第一种参数修改:保持dx也不变,确定能输出999个*号的心形图案的最小的dy。结果保留7位小数。
(1)首先,提点一下此问题的解决思路,以便更好阅读程序。更详细的算法解读可以到下面的代码后面看算法描述。按问题要求,dx 不变,要去确定最小的 dy,这里其实提示了你 dy 要在一个基数上向上增加(其实降低了难度,如果要判断 dy 要增加,即 y 要减少,还需做一两次测试才能确定),基本思路就是,不停增加 y 的变化量——即增加 dy,因为要保留 7 位小数,于是只要 dy 的增加量是0.0000001 即可。这样得到最小的可以打印出心形的dy。
计算最小dy的代码:
【算法描述】结合程序,简单描述一下,
(1)首先,为了每一个 dy,我们都要尝试去“打印”一遍心型循环(打印加引号是指我们不必真要输出,要不然命令行很难看,我们只走循环,并对计数,走完了循环且等于了 999 就可结束。
(2)其次,我们就不能固定 dy 了,而要让 dy 变化,且因为按题意,只要 7 位小数,所以 dy的变化步长取为 0.0000001f。
(3)再次,dy 到底是增量还是减量呢?这里就有一个诀窍,在问题 1 的程序基础上,把 dy 增大或减小,观察号计数,最终确定 dy 可以在 0.05 基础上,不停累加 0.0000001f,对每次累加,都去执行“打印”心型程序,然后判断该程序循环走完时号计数是否是 999,如果执行过程中号计数超过了999 就立即返回,增量到下一个 dy;如果程序循环走完时,*号数不是 999 也要返回不满足要求的标记。
(4)最后,观察主程序,套用一个大循环去枚举 dy 的每一个 0.0000001f 增量。因为是 7 位小数,所以理论上最大到 Integer.MAX_VALUE(即 2147483647)就可以了。
public class B03EE2s1 { /** * 适用暴力获取指定total数的心型参数 * @param s0//@Param:用来在DAO层中声明参数 * @param dx * @param dy * @param total * @return */ public static boolean heart(float s0, float dx, float dy, int total){ int stars = 0; int cx = 0, cy = 0; // 问y 、 x 总共循环了多少次 float e0 = -s0; for (float y = s0; y > e0; y -= dy, cy++) { cx = 0; for (float x = e0; x < s0; x += dx, cx++) { float a = x * x + y * y - 1; if ((a * a * a - x * x * y * y * y) <= 0.0) { //System.out.print("*"); stars++; // *计数 /* 此处不能用=比较,原因在于等于999的*号未必 * 就是心形的图案,必须是走完循环才能出心形图案。 */ if(stars > total){ return false; // 已经超过,直接返回 } } else{ //System.out.print(" ");//这里个源文件主要来计算dy值不是来输出的所以这里可以不用输出直接空过 } } } System.out.printf("cx=%d, cy=%d, stars=%d%n", cx, cy, stars); if(stars != total){ return false; // 不等于返回false }else { return true; } } public static void main(String[] args) { /* 为了找到含有999颗*的心型参数,不断枚举——暴力方式。 */ int total = 999, loops = 0; // *的总数,loops=循环次数,超过int的MAX退出for /* 0.1是736颗,再试一下0.06,也是*增多,但是比0.05要少,所以应该增量dy,故原版程 序y是要不停往下递减才能让*增多 */ float dy = 0.05f; float sdy = 0.0000001f; // 保留7位,我们就从这个开始对 float s0 = 1.5f, dx = 0.05f; for(; loops++ < Integer.MAX_VALUE; dy += sdy) { System.out.printf("loops=%d, dx=%.7f, dy=%.7f%n", loops, dx, dy); if(heart(s0, dx, dy, total)) { break; } } } }
即可得到最后两行的结果是:
可知最小 dy 的值就是红色线所示。不用再往大的 dy 找了。
(2)接着打印出来999个*心形
import java.util.*; public class HeartV2 { /* 爱心的公式 (x²+y²-1)³-x²*y³=0 */ public static void main(String[] args) { int stars = 0; int cx = 0, cy = 0; // 问y 、 x 总共循环了多少次 float dx = 0.05f; float dy = 0.0735288f; /*【2】 f;*/ /* 原dy = 0.1f,这个有7位小数的float 数dy是能输出999个*之心图案的最小数。f表示单精度浮点类型常量后缀 */ for (float y = (float)1.5; y > -1.5; y -= dy, cy++){ cx = 0; for (float x = (float) -1.5; x < 1.5; x += dx, cx++){ float a = x * x + y * y - 1; if ((a * a * a - x * x * y * y * y) <= 0.0){ System.out.print("*");// 心形区域内打印* stars++; } else{ System.out.print(" "); // 心形区域外打印空格 } } System.out.println(""); // 本行结束,换行准备下一行的输出 } // 打印包括*数的信息 System.out.printf("stars=%d, cx=%d, cy=%d%n", stars, cx, cy); } }
执行结果:
此时:stars=999, cx=61, cy=41
最后一行显示有999个*号,而且x循环不变,但是纵向的y循环变成了41次,这就导致输出的心形图案呈现廋扁状。
你的意中人未必满意哟!
△第二种参数修改:观察原版程序及原理和输出,我们调整dx和dy并保持dx:dy=1:2不变,确定能输出999个*号的心形图案的最小的dx和dy。结果保留7位小数。
这个问题比问题 2 稍微复杂“一丢丢”,即保持 dy:dx=2 即可,这样确定了 dx 就知道 dy。
(1)先计算dx和dy代码(跟修改参数一时的算法思想差不多):
public class B03EE2s3 { /** * 适用暴力获取指定total数的心型参数 * @param s0//@Param:用来在DAO层中声明参数 * @param dx * @param dy * @param total * @return */ public static boolean heart(float s0, float dx, float dy, int total){ int stars = 0; int cx = 0, cy = 0; // 问y 、 x 总共循环了多少次 float e0 = -s0; for (float y = s0; y > e0; y -= dy, cy++) { cx = 0; for (float x = e0; x < s0; x += dx, cx++) { float a = x * x + y * y - 1; if ((a * a * a - x * x * y * y * y) <= 0.0) { //System.out.print("*"); stars++; // *计数 /* 此处不能用=比较,原因在于等于999的*号未必 * 就是心形的图案,必须是走完循环才能出心形图案。 */ if(stars > total){ return false; // 已经超过,直接返回 } } else{ //System.out.print(" ");//这里个源文件主要来计算dy值不是来输出的所以这里可以不用输出直接空过 } } } System.out.printf("cx=%d, cy=%d, stars=%d%n", cx, cy, stars); if(stars != total){ return false; // 不等于返回false }else { return true; } } public static void main(String[] args) { /* 为了找到含有999颗*的心型参数,不断枚举——暴力方式。 */ int total = 999, loops = 0; // *的总数,loops=循环次数,超过int的MAX退出for /* 0.1是736颗,再试一下0.06,也是*增多,但是比0.05要少,所以应该增量dy,故原版程 序y是要不停往下递减才能让*增多 */ float dx = 0.05f; float sdx = 0.0000001f; // 保留7位,我们就从这个开始对 float s0 = 1.5f, dy = 2*dx; for(; loops++ < Integer.MAX_VALUE; dx -= sdx) { System.out.printf("loops=%d, dx=%.7f, dy=%.7f%n", loops, dx, dy); if(heart(s0, dx, dy, total)) { break; } } } }
执行结果:
(2)接着打印出来999个*心形
import java.util.*; public class HeartV3 { /* 爱心的公式 (x²+y²-1)³-x²*y³=0 */ public static void main(String[] args) { int stars = 0; int cx = 0, cy = 0; // 问y 、 x 总共循环了多少次 float dx = 0.0368397f; float dy = 0.1000000f; /*【2】 f;*/ /* 原dy = 0.1f,这个有7位小数的float 数dy是能输出999个*之心图案的最小数。f表示单精度浮点类型常量后缀 */ for (float y = (float)1.5; y > -1.5; y -= dy, cy++){ cx = 0; for (float x = (float) -1.5; x < 1.5; x += dx, cx++){ float a = x * x + y * y - 1; if ((a * a * a - x * x * y * y * y) <= 0.0){ System.out.print("*");// 心形区域内打印* stars++; } else{ System.out.print(" "); // 心形区域外打印空格 } } System.out.println(""); // 本行结束,换行准备下一行的输出 } // 打印包括*数的信息 System.out.printf("stars=%d, cx=%d, cy=%d%n", stars, cx, cy); } }
执行结果:
********************** ********************** ****************************************************** ********************************************************** ************************************************************ ************************************************************* ************************************************************** ************************************************************** ************************************************************* ************************************************************ *********************************************************** ********************************************************* ****************************************************** *************************************************** ************************************************ ******************************************** *************************************** ********************************** **************************** ********************* ************* *****
stars=999, cx=82, cy=30
完事哈哈哈啊哈哈哈