【4.16】參考答案:
main( )
{ int i,j,n;
printf("\nPlease Enter n: ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{ for(j=1;j<=n+i-2;j++)
if(j==n-i+1) printf("*");
else printf(" ");
printf("*\n");
}
}
【4.17】分析:首先對(duì)圖形進(jìn)行設(shè)計(jì),坐標(biāo)的X軸和Y軸分別對(duì)應(yīng)屏幕的列和行,一個(gè)正弦函數(shù)的周期為0~360度,我們把一個(gè)步長(zhǎng)定義為10度,打印時(shí)每換一行等于函數(shù)的自變量增加10度;屏幕的列寬為80,函數(shù)值為0對(duì)應(yīng)屏幕的第40列,sin(x)的值在-1~1,變換成列數(shù)為以0為中心的-30~30,對(duì)應(yīng)屏幕上第10~70列。設(shè)計(jì)程序時(shí),控制換行的自變量i乘以10得到正弦函數(shù)的X值,調(diào)用庫(kù)函數(shù)sin()求出函數(shù)值再乘以30輸出的列寬,因?yàn)槲覀円云聊坏牡?0列為0點(diǎn),故再加上40得到應(yīng)在屏幕上顯示的點(diǎn)。
參考答案:
#define PAI 3.14159
#include
main( )
{ double x;
int y,i,yy;
for(i=1;i<80;i++) /* 打印圖形的第一行 */
if(i==40) printf("*"); /* i控制打印的列位置 */ else printf("-");
printf("\n");
for(x=10.0;x<=360.0;x+=10.) /* 從10度到360度 */
{ y = 40+30*sin(x*PAI/180.0); /* 計(jì)算對(duì)應(yīng)的列 */
yy = 40>y ? 40 : y; /* 下一行要打印的字符總數(shù) */
for (i=1;i<=yy;i++) /* 控制輸出圖形中的一行 */
{ if(i==y) printf("*"); /* i控制打印的列位置 */
else if(i==40) printf("|"); /* 打印中心的豎線 */
else printf(" ");
}
printf("\n");
}
}
【4.18】分析:首先設(shè)計(jì)屏幕圖形,如果預(yù)計(jì)圓形在屏幕上打印20行,所以定義圓的直徑就是20,半徑為10,圓的方程是X2×Y2=R2,因?yàn)閳D形不是從中心開始打印而是從邊沿開始,所以Y從10變化到-10,根據(jù)方程求出X,對(duì)求得的X值再根據(jù)屏幕行寬進(jìn)行必要的調(diào)整得到應(yīng)打印的屏幕位置。
參考答案:
#include
main( )
{ double y;
int x,m;
for(y=10;y>=-10;y--) /* 圓的半徑為10 */
{ m = 2.5 * sqrt(100-y*y); /* 計(jì)算行y對(duì)應(yīng)的列坐標(biāo)m */
for(x=1;x<30-m;x++)
printf(" "); /* 輸出圓左側(cè)的空白 */
printf("*"); /* 輸出圓的左側(cè) */
for(;x<30+m;x++)
printf(" "); /* 輸出圓的空心部分 */
printf("*\n"); /* 輸出圓的右側(cè) */
}
}
【4.19】參考答案:
#include
#include
main( )
{ double y;
int x, m, n, yy;
for( yy=0;yy<=20;yy++)
{ y = 0.1*yy;
m = acos(1-y)*10;
n = 45 * (y-1)+31;
for( x=0;x<=62;x++ )
if( x==m && x==n ) printf("+");
else if(x==n) printf("+");
else if(x==m || x==62-m) printf("*");
else printf(" ");
printf("\n");
}
}
【4.20】分析:編程的關(guān)鍵為兩點(diǎn),一是使用控制輸出的行和列,這方面的內(nèi)容在前面已經(jīng)敘述,另一點(diǎn)是輸出的數(shù)字和所在行、列關(guān)系。此題第一行輸出的數(shù)字恰好是列數(shù),從第二行起每行的數(shù)字均比上一行增n。
參考答案:
main( )
{ int i,j,n;
printf("\nPlease Enter n: ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
printf("%4d",(i-1)*n+j);
printf("\n");
}
}
【4.21】分析:此題的關(guān)鍵是找到輸出數(shù)字和行、列數(shù)的關(guān)系。審查圖形中每行中數(shù)字的關(guān)系發(fā)現(xiàn),右邊數(shù)字和前面數(shù)字之差逐次增1;同列數(shù)字依然是這樣的關(guān)系,編程的關(guān)鍵轉(zhuǎn)換為找到每一行左方的第一個(gè)數(shù)字,然后利用行和列的循環(huán)變量進(jìn)行運(yùn)算就可得到每個(gè)位置的數(shù)字。用ai,j此表示第i行第j列的數(shù)字,則a11=1;由第i行第一列的數(shù)字推出第i+1行第一列的數(shù)字是ai+1,1 = ai,1+i;同樣由第j列推出第j+1列的數(shù)字是ai,j+1 = ai,j+i+j。另外只有當(dāng)j
參考答案:
main( )
{ int i,j,m,n,k=1; /* k是第一列元素的值 */
printf("Please enter m=" ");
scanf("%d",&m);
for(i=1;i<=m;i++)
{ n=k; /* n第i行中第1個(gè)元素的值 */
for(j=1;j<=m-i+1;j++)
{ printf("%3d",n);
n = n+i+j; /* 計(jì)算同行下一個(gè)元素的值 */
}
printf("\n");
k=k+i; /* 計(jì)算下一行中第1個(gè)元素 */
}
}
【4.22】參考答案:
main( )
{ int i,j,n;
printf("\nPlease Enter n: ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
if(j<=i) printf(" 1");
else printf("%3d",j-i+1);
printf("\n");
}
}
【4.23】分析:可用不同的方案解決此問(wèn)題,為了開闊讀者的思路,這里給出了兩個(gè)參考答案,其中第二個(gè)答案是使用了遞歸方法。
方案一:
首先尋找數(shù)字輸出數(shù)字和行列的關(guān)系。
每圈有四個(gè)邊,把每邊的最后一個(gè)數(shù)字算為下邊的開始,最外圈每邊數(shù)字個(gè)數(shù)是n-1個(gè),以后每邊比外邊一邊少兩個(gè)數(shù)字。
因?yàn)閿?shù)字是一行一行輸出的,再分析每行數(shù)字的規(guī)律。實(shí)際沒(méi)有的數(shù)字有三種規(guī)律:位于對(duì)角線之間的數(shù)字是上半圖增一,下半圖減一。對(duì)角線左側(cè)的各列,右側(cè)比左側(cè)增加了一圈數(shù)字,例如數(shù)字39和它左側(cè)的22比較,數(shù)字39所在的圈每邊4個(gè)數(shù)字,左側(cè)22加上一圈16個(gè)數(shù)字在加1就是39。同理,對(duì)角線右側(cè)的各列,則減少一圈的數(shù)字個(gè)數(shù)。
根據(jù)以上分析,用兩個(gè)對(duì)角線將圖形分為四個(gè)區(qū)域,如下圖所示,圖中黑斜體字為對(duì)角線上的數(shù)字。
1 2 3 4 5 6 7
24 25 26 27 28 29 8
23 40 41 42 43 30 9
22 39 48 49 44 31 10
21 38 47 46 45 32 11
20 37 36 35 34 33 12
19 18 17 16 15 14 13
為敘述方便我們稱四個(gè)區(qū)域?yàn)樯、下、左、右區(qū)。設(shè)i、j為行列號(hào),n為圖形的總行數(shù),則滿足各區(qū)的范圍是,上區(qū):j>=i 且 j<=n-i+1 ;下區(qū):j<=i 且 j>=n-i+1 ;左區(qū):ji 且 j>n-i+1 。
現(xiàn)在問(wèn)題是,如果知道一行在不同區(qū)域開始第一個(gè)位置的數(shù)字,然后該區(qū)后續(xù)的數(shù)字就可利用前面分析的規(guī)律得到。
對(duì)于右區(qū)開始各行第一個(gè)數(shù)字最易求出,為4*(n-1)-i+1。后續(xù)一個(gè)和同行前一個(gè)數(shù)字之差是4*[n-1-(j-1)*2]+1,其中方括號(hào)內(nèi)是每邊的數(shù)字個(gè)數(shù)。
對(duì)角線上的數(shù)字是分區(qū)點(diǎn),對(duì)角線上相臨數(shù)字仍然相差一圈數(shù)字個(gè)數(shù),讀者自行分析得到計(jì)算公式。
右區(qū)開始的第一個(gè)數(shù)字可以從上區(qū)結(jié)束時(shí)的數(shù)字按規(guī)律求出。
下述程序用變量s保存分區(qū)對(duì)角線上的數(shù)字。
參考答案一:
main()
{ int i,j,k,n,s,m,t;
printf("Please enter n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
{ s=(i<=(n+1)/2)? 1:3*(n-(n-i)*2-1)+1;
m=(i<=(n+1)/2)? i:n-i+1; /* m-1是外層圈數(shù) */
for(k=1;k for(j=1;j<=n;j++) { if(j>=n-i+1 && j<=i) /* 下區(qū) */ t=s-(j-(n-i))+1; if(j>=i && j<=n-i+1) /* 上區(qū) */ t=s+j-i; if(j>i && j>n-i+1) /* 右區(qū) */ t-=4*(n-2*(n-j+1))+1; if(j
{ if(j==1) t=4*(n-1)-i+2; else t+=4*(n-2*j+1)+1; } printf("%4d",t); } printf("\n"); } } 方案二: 根據(jù)本題圖形的特點(diǎn),我們可以構(gòu)造一個(gè)遞歸算法。我們可以將邊長(zhǎng)為N的圖形分為兩部分:第一部分最外層的框架,第二部分為中間的邊長(zhǎng)為N-2的圖形。 對(duì)于邊長(zhǎng)為N的正方型,若其中每個(gè)元素的行號(hào)為i(1≤i≤N),列號(hào)為j(1≤j≤N),第1行第1列元素表示為a1,1(a11=1),則有: 對(duì)于最外層的框架可以用以下數(shù)學(xué)模型描述: 上邊: a1,j=a1,1+j-1 (j≠1) 右邊: ai,N=a1,1+N+i-2 (i≠1) 下邊: ai,1=a1,1+4N-i-3 (i≠1) 左邊: aN,j=a1,1+3N-2-j (j≠1) 對(duì)于內(nèi)層的邊長(zhǎng)為N-2的圖形可以用以下數(shù)學(xué)模型描述: 左上角元素:ai,i=ai-1,i-1+4(N-2i-1) (i>1) 若令:ai,j=fun(ai-1,i-1+4(N-2i-1),當(dāng):i<(N+1)/2且j<(N+1)/2時(shí),min=MIN(i,j),則有: a2,2 = fun(a1,1, min, min, n) ai,j=fun(a2,2, i-min+1, j-min+1, n-2*(min-1) ) 我們可以根據(jù)上述原理,分別推導(dǎo)出i和j為其它取值范圍時(shí)的min取值。根據(jù)上述遞歸公式,可以得到以下參考程序。 參考答案二: #include #define MIN(x,y) (x>y) ? (y) : (x) fun ( int a11, int i, int j, int n) { int min, a22; if( i==j && i<=1 ) return(a11); else if( i==j && i<=(n+1)/2) return( fun(a11,i-1,i-1,n)+4*(n-2*i+3)); else if( i==1 && j!=1) return( a11+j-1 ); else if( i!=1 && j==n) return( a11+n+i-2 ); else if( i!=1 && j==1 ) return ( a11+4*n-3-i ); else if( i==n && j!=1 ) return ( a11+3*n-2-j ); else { if(i>=(n+1)/2 && j>=(n+1)/2) min = MIN(n-i+1,n-j+1); else if(i<(n+1)/2 && j>=(n+1)/2) min = MIN(i,n-j+1); else if(i>=(n+1)/2 && j<(n+1)/2) min = MIN(n-i+1,j); else min = MIN(i,j); a22 = fun(a11,min,min,n); return(fun(a22, i-min+1, j-min+1, n-2*(min-1))); } } main() { int a11=1, i, j, n; printf("Enter n="); scanf("%d", &n); for(i=1; i<=n; i++) { for(j=1; j<=n; j++) printf("%4d", fun(a11,i,j,n) ); printf("\n"); } } 【4.24】分析:此題的關(guān)鍵還是要找到輸出數(shù)字aij和行列數(shù)i、j的關(guān)系。為此將圖形分為四個(gè)區(qū)域如下圖: 3 3 3 3 3 3 2 2 2 3 3 2 1 2 3 3 2 2 2 3 3 3 3 3 3 (此圖n為5) 在左上區(qū)域,即i<=(n+1)/2、j<=(n+1)/2時(shí),輸出數(shù)字為(n+1)/2-i+1和(n+1)/2-j+1中的大者,記為max{(n+1)/2-i+1,(n+1)/2-j+1};在右上區(qū),即i<=(n+1)/2、j>(n+1)/2時(shí), 輸出數(shù)字為max{(n+1)/2-i+1,j-n/2};在左下區(qū),即i>(n+1)/2、j<=(n+1)/2時(shí),輸出數(shù)字為max{i-n/2,(n+1)/2-j+1};在右下區(qū),即i>(n+1)/2、j>(n+1)/2時(shí),輸出數(shù)字為max{i-n/2,j-n/2}。 參考答案: #define max(x,y) ((x)>(y)?(x):(y)) main( ) { int i,j,n; printf("\nPlease Enter n:"); scanf("%d",&n); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) if(i<=(n+1)/2) if(j<=(n+1)/2) printf("%4d",max((n+1)/2-i+1,(n+1)/2-j+1)); else printf("%4d",max((n+1)/2-i+1,j-n/2)); else if(j<=(n+1)/2) printf("%4d",max(i-n/2,(n+1)/2-j+1)); else printf("%4d",max(i-n/2,j-n/2)); printf("\n"); } } 【4.25】分析:前面我們已經(jīng)見到過(guò)上下對(duì)稱的圖形,這是一個(gè)左右對(duì)稱的圖形,垂直中心線上的數(shù)字恰好是行號(hào),在每行位于圖形垂直中心線左方的數(shù)字是逐漸增加的,而右方是逐漸減小的。j==i是分區(qū)的標(biāo)志,左方輸出數(shù)字就是列數(shù)j,而右方的數(shù)字從i開始逐步減小1。 參考答案: main() { int i,j; for(i=1;i<=9;i++) { for(j=1;j<=9-i;j++) printf(" "); for(j=1;j<=i;j++) printf("%2d",j); for(j=i-1;j>=1;j--) printf("%2d",j); printf("\n"); } } 【4.26】分析:這類輸出字符的圖形和輸出數(shù)字的圖形考慮是近似的,因?yàn)樽址腁SCII碼就是一個(gè)整數(shù)。在字符碼值的變化過(guò)程中,應(yīng)該注意應(yīng)該判斷碼值是否超出字符的范圍,進(jìn)行必要的處理,為了保持程序的簡(jiǎn)潔,本題沒(méi)有考慮這個(gè)問(wèn)題,在下題里對(duì)這個(gè)問(wèn)題進(jìn)行了處理。 參考答案: main( ) { char c='Z'; int i,j,n; printf("\nPlease Enter n:"); scanf("%d",&n); for(i=1;i<=n;i++) { for(j=1;j<=n+i-2;j++) if(j==n-i+1) printf("%c",c--); else printf(" "); printf("%c\n",c--); } for(i=1;i { for(j=1;j<=2*(n-1)-i;j++) if(j==i+1) printf("%c",c--); else printf(" "); printf("%c\n",c--); } } 【4.27】分析:此題與上題相近,區(qū)別在于輸出時(shí)字符的ASCII碼值的變化在圖形的中間一行為最大,同時(shí)一行的兩個(gè)字符是相同的。程序考慮在輸入字符時(shí)設(shè)計(jì)了一個(gè)循環(huán),保證輸入的是英文字母。字符變化后進(jìn)行了處理,程序中使用條件運(yùn)算。在字符碼值增加的過(guò)程中,首先判斷是大寫還是小寫字符,然后判斷字符碼值是否超出英文字母z(或Z),如果超出則重新賦為a(或A);在輸出圖象下半部分時(shí),ASCII碼值減少用同樣的思路進(jìn)行判斷。在判斷字符大小寫(條件語(yǔ)句的第一個(gè)判斷)時(shí),用的是兩個(gè)不同的值,請(qǐng)讀者自行思考為什么,用同一個(gè)值是否可以? 參考答案: main( ) { char c; int i,j,n; do { printf("\nPlease Enter n,char:"); scanf("%d,%c",&n,&c); }while(c<'A'||c>'Z'&&c<'a'||c>'z'); for(i=1;i<=n;i++) { for(j=1;j<=n+i-2;j++) if(j==n-i+1) printf("%c",c); else printf(" "); printf("%c\n",c++); c=c<'a'?(c>'Z'?'A':c):(c>'z'?'a':c); } c-=2; c=c<'Z'?(c<'A'?'Z':c):(c<'a'? 'z':c); for(i=1;i { for(j=1;j<=2*(n-1)-i;j++) if(j==i+1) printf("%c",c); else printf(" "); printf("%c\n",c--); c=c<'Z'?(c<'A'?'Z':c):(c<'a'? 'z':c); } } 【4.28】參考答案: #define max(x,y) ((x)>(y)?(x):(y)) main( ) { char c; int i,j,n; do { printf("\nPlease Enter n,char:"); scanf("%d,%c",&n,&c); }while(c<'A'||c>'Z'&&c<'a'||c>'z'); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) if(i<=(n+1)/2) if(j<=(n+1)/2) printf(" %c",c-max((n+1)/2-i+1,(n+1)/2-j+1)+(n+1)/2); else printf(" %c",c-max((n+1)/2-i+1,j-n/2)+(n+1)/2); else if(j<=(n+1)/2) printf(" %c",c-max(i-n/2,(n+1)/2-j+1)+(n+1)/2); else printf(" %c",c-max(i-n/2,j-n/2)+(n+1)/2); printf("\n"); } } 【4.29】參考答案: #define max(x,y) ((x)>(y)?(x):(y)) main( ) { char c; int i,j,n; do { printf("\nPlease Enter n,char:"); scanf("%d,%c",&n,&c); }while(c<'A'||c>'Z'&&c<'a'||c>'z'); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) if(i<=(n+1)/2) if(j<=(n+1)/2) printf(" %c",c-max((n+1)/2-i+1,(n+1)/2-j+1)+1); else printf(" %c",c-max((n+1)/2-i+1,j-n/2)+1); else if(j<=(n+1)/2) printf(" %c",c-max(i-n/2,(n+1)/2-j+1)+1); else printf(" %c",c-max(i-n/2,j-n/2)+1); printf("\n"); } } 【4.30】參考答案: #include main() { int i, j; for(i=1;i<10;i++) printf("%4d",i); printf("\n--------------------------------------\n"); for(i=1;i<10;i++) { for(j=1;j<10;j++) if(j
else printf( "%4d" , i*j); printf("\n"); } }