[轉]100個經典C語言程式(益智類問題)
目錄:
1.繪製餘弦曲線
2.繪製餘弦曲線和直線
3.繪製圓
4.歌星大獎賽
5.求最大數
6.高次方數的尾數
8.借書方案知多少
9.楊輝三角形
10.數制轉換
11.打魚還是晒網
12.抓交通肇事犯
13.該存多少錢
14.怎樣存錢利最大
15.捕魚和分魚
16.出售金魚
1.7 分數四則運算
17.平分七筐魚
18.有限5位數
19. 8 除不盡的數
21.4位反序數
22.求車速
23.阿姆斯特朗數
24.完全數
26.親密數
27.自守數
28.迴文數
29.求具有abcd=(ab+cd)2性質的四位數
30.求素數
31.歌德巴赫猜想
32.要發就發
35.素數幻方
36.百錢百雞問題
37.愛因斯坦的數學題
39.年齡幾何
38.換分幣
40.三色球問題
41.馬克思手稿中的數學題
42.最大公約數和最小公倍數
43.分數比較
44.分數之和
45.將真分數分解為埃及分數
46.列出真分數序列
47.計算分數的精確值
51.誰是竊賊
52.黑與白
53.迷語博士的難題(1)
54.迷語博士的難題(2)
55.哪個大夫哪天值班
56.區分旅客國籍
57.誰家孩子跑最慢
58.拉丁方陣
59.填表格
60.1~9分成1:2:3的三個3位數
61.1~9組成三個3位的平方數
62.由8個整數形成奇特的立方體
63.減式還原
64.乘式還原
65.乘式還原(2)
66.除式還原(1)
67.除式還原(2)
68.九位累進可除數
69.魔術師的猜牌術(1)
70.魔術師的猜牌術(2)
71.約瑟夫問題
72.郵票組合
73 和數能表示1~23的5個正整數
74.可稱1~40磅的4塊砝碼
75.10個小孩分糖果
76.小明買書
77.波鬆瓦酒的分酒趣題
78.求π的近似值
79.求π的近似值(2)
80.奇數平方的一個有趣性質
81.角谷猜想
82.四方定理
83.卡布列克常數
84.尼科徹斯定理
85.迴文數的形成
86.自動發牌
87.黑白子交換
88.常勝將軍
89.搶 30
90.搬山遊戲
91.人機猜數遊戲
92.人機猜數遊戲(2)
93.漢諾塔
94.兎子產子
95.將阿拉伯數字轉換為羅馬數字
96.選美比賽
97.滿足特異條件的數列
98. 八皇后問題
99.超長正整數的加法
100. 數字移動
1.繪製餘弦曲線
在螢幕上用“*”顯示0~360度的餘弦函式cos(x)曲線*問題分析與演算法設計如果在程式中使用陣列,這個問題十分簡單。但若規定不能使用陣列,問題就變得不容易了。
關鍵在於餘弦曲線在0~360度的區間內,一行中要顯示兩個點,而對一般的顯示器來說,只能按行輸出,即:輸出第一行資訊後,只能向下一行輸出,不能再返回到上一行。
為了獲得本文要求的圖形就必須在一行中一次輸出兩個“*”。 為了同時得到餘弦函式cos(x)圖形在一行上的兩個點,考慮利用cos(x)的左右對稱性。將螢幕的行方向定義為x,
列方向定義為y,則0~180度的圖形與180~360度的圖形是左右對稱的,若定義圖形的總寬度為62列,計算出x行0~180度時y點的座標m,
那麼在同一行與之對稱的180~360度的y點的座標就應為62-m。程式中利用反餘弦函式acos計算座標(x,y)的對應關係。 使用這種方法編出的程式短小精煉,
體現了一定的技巧。
*程式說明與註釋
#include<stdio.h>
#include<math.h>
void main()
{
double y;
int x,m;
for(y=1;y>=-1;y-=0.1)
{
m=acos(y)*10;
for(x=1;x<m;x++)printf(" ");
printf("*");
for(;x<62-m;x++)printf("");
printf("*\\n");
}
}
2.繪製餘弦曲線和直線
在螢幕上顯示0~360度的cos(x)曲線與直線f(x)=45*(y-1)+31的迭加圖形。其中cos(x)圖形用“*”表示,f(x)用“+”表示,在兩個圖形相交的點上則用f(x)圖形的符號。
*問題分析與演算法設計
本題可以在上題的基礎上進行修改。圖形迭加的關鍵是要在分別計算出同一行中兩個圖形的列方向點座標後,正確判斷相互的位置關係。為此,可以先判斷圖形的交點,再分別控制列印兩個不同的圖形。
*程式註釋與說明
#include<stdio.h>
#include<math.h>
void 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("+");
elseif(x==n) printf("+");
elseif(x==m||x==62-m) printf("*");
else printf("");
printf("\\n");
}
}
--------------------------------------------------------------------------------
3.繪製圓
在螢幕上用“*”畫一個空心的圓
*問題分析與演算法設計
列印圓可利用圖形的左右對稱性。根據圓的方程:
R*R=X*X+Y*Y
可以算出圓上每一點行和列的對應關係。
*程式說明與註釋
#include<stdio.h>
#include<math.h>
void main()
{
double y;
int x,m;
for(y=10;y>=-10;y--)
{
m=2.5*sqrt(100-y*y);
for(x=1;x<30-m;x++)printf(" ");
printf("*");
for(;x<30+m;x++)printf(" ");
printf("*\\n");
}
}
4.歌星大獎賽
在歌星大獎賽中,有10個評委為參賽的選手打分,分數為1~100分。選手最後得分為:去掉一個最高分和一個最低分後其餘8個分數的平均值。請編寫一個程式實現。
*問題分析與演算法實現
這個問題的演算法十分簡單,但是要注意在程式中判斷最大、最小值的變數是如何賦值的。
*程式說明與註釋
#include<stdio.h>
void main()
{
intinteger,i,max,min,sum;
max=-32768;
min=32767;
sum=0;
for(i=1;i<=10;i++)
{
printf("Inputnumber %d=",i);
scanf("%d",&integer);
sum+=integer;
if(integer>max)max=integer;
if(integer<min)min=integer;
}
printf("Canceledmax score:%d\\nCanceled min score:%d\\n",max,min);
printf("Averagescore:%d\\n",(sum-max-min)/8);
}
*執行結果
Input number1=90
Input number2=91
Input number3=93
Input number4=94
Input number5=90
Input number6=99
Input number7=97
Input number8=92
Input number9=91
Input number10=95
Canceled maxscore:99
Canceled minscore:90
Averagescore:92
*思考題
題目條件不變,但考慮同時對評委評分進行裁判,即在10個評委中找出最公平(即評分最接返平均分)和最不公平(即與平均分的差距最大)的評委,程式應該怎樣實現?
--------------------------------------------------------------------------------
5.求最大數
問555555的約數中最大的三位數是多少?
*問題分析與演算法設計
根據約數的定義,對於一個整數N,除去1和它自身外,凡能整除N的數即為N的約數。因此,最簡單的方法是用2到N-1之間的所有數去除N,即可求出N的全部約數。本題只要求取約數中最大的三位數,則其取值範圍可限制在100到999之間。
*程式說明與註釋
#include<stdio.h>
void main()
{
long i;
int j;
printf("Pleaseinput number:");
scanf("%ld",&i);
for(j=999;j>=100;j--)
if(i%j==0)
{
printf("Themax factor with 3 digits in %ld is:%d,\\n",i,j);
break;
}
}
*執行結果
輸入:555555
輸出:The maxfactor with 3 digits in 555555 is:777
6.高次方數的尾數
求13的13次方的最後三位數
*問題分析與演算法設計
解本題最直接的方法是:將13累乘13次方擷取最後三位即可。
但是由於計算機所能表示的整數範圍有限,用這種“正確”的演算法不可能得到正確的結果。事實上,題目僅要求最後三位的值,完全沒有必要求13的13次方的完整結果。
研究乘法的規律發現:乘積的最後三位的值只與乘數和被乘數的後三位有關,與乘數和被乘數的高位無關。利用這一規律,可以大大簡化程式。
*程式說明與註釋
#include<stdio.h>
void main()
{
inti,x,y,last=1;
printf("InputX and Y(X**Y):");
scanf("%d**%d",&x,&y);
for(i=1;i<=y;i++)
last=last*x%1000;
printf("Thelast 3 digits of %d**%d is:%d\\n",x,y,last%1000);
}
*執行結果
Input X andY(X**Y):13**13
The last 3 digitsof 13**13 is:253
Input X andY(X**Y):13**20
The last 3 digitsof 13**20 is:801
--------------------------------------------------------------------------------
8.借書方案知多少
小明有五本新書,要借給A,B,C三位小朋友,若每人每次只能借一本,則可以有多少種不同的借法?
*問題分析與演算法設計
本問題實際上是一個排列問題,即求從5箇中取3個進行排列的方法的總數。首先對五本書從1至5進行編號,然後使用窮舉的方法。假設三個人分別借這五本書中的一本,當三個人所借的書的編號都不相同時,就是滿足題意的一種借閱方法。
*程式說明與註釋
void main()
{
int a,b,c,count=0;
printf("Thereare diffrent methods for XM to distribute books to 3 readers:\\n");
for(a=1;a<=5;a++)
for(b=1;b<=5;b++)
for(c=1;a!=b&&c<=5;c++)
if(c!=a&&c!=b)
printf(count%8?"%2d:%d,%d,%d ":"%2d:%d,%d,%d\\n ",++count,a,b,c);
}
*執行結果
There are diffrentmethods for XM to distribute books to 3 readers:
1:1,2,3 2:1,2,4 3:1,2,5 4:1,3,2 5: 1,3,4
6:1,3,5 7:1,4,2 8:1,4,3 9:1,4,5 10:1,5,2
11:1,5,3 12:1,5,4 13:2,1,3 14:2,1,4 15:2,1,5
16:2,3,1 17:2,3,4 18:2,3,5 19:2,4,1 20:2,4,3
21:2,4,5 22:2,5,1 23:2,5,3 24:2,5,4 25:3,1,2
26:3,1,4 27:3,1,5 28:3,2,1 29:3,2,4 30:3,2,5
31:3,4,1 32:3,4,2 33:3,4,5 34:3,5,1 35:3,5,2
36:3,5,4 37:4,1,2 38:4,1,3 39:4,1,5 40:4,2,1
41:4,2,3 42:4,2,5 43:4,3,1 44:4,3,2 45:4,3,5
46:4,5,1 47:4,5,2 48:4,5,3 49:5,1,2 50:5,1,3
51:5,1,4 52:5,2,1 53:5,2,3 54:5,2,4 55:5,3,1
56:5,3,2 57:5,3,4 58:5,4,1 59:5,4,2 60:5,4,3
9.楊輝三角形
在螢幕上顯示楊輝三角形
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
......................................
*問題分析與演算法設計
楊輝三角形中的數,正是(x+y)的N次方冪展開式各項的係數。本題作為程式設計中具有代表性的題目,求解的方法很多,這裡僅給出一種。
從楊輝三角形的特點出發,可以總結出:
1)第N行有N+1個值(設起始行為第0行)
2)對於第N行的第J個值:(N>=2)
當J=1或J=N+1時:其值為1
J!=1且J!=N+1時:其值為第N-1行的第J-1個值與第N-1行第J個值之和
將這些特點提煉成數學公式可表示為:
1 x=1或x=N+1
c(x,y)=
c(x-1,y-1)+c(x-1,y) 其它
本程式應是根據以上遞迴的數學表示式編制的。
*程式說明與註釋
#include<stdio.h>
void main()
{
int i,j,n=13;
printf("N=");
while(n>12)
scanf("%d",&n);
for(i=0;i<=n;i++)
{
for(j-0;j<24-2*i;j++)printf(" ");
for(j=1;j<i+2;j++)printf("%4d",c(i,j));
printf("\\n");
}
}
void int c(int x,inty)
{
int z;
if((y==1)||(y==x+1)) return1;
z=c(x-1,y-1)+c(x-1,y);
return z;
}
--------------------------------------------------------------------------------
10.數制轉換
將任一整數轉換為二進位制形式
*問題分析與演算法設計
將十進位制整數轉換為二進位制的方法很多,這裡介紹的實現方法利用了C語言能夠對位進行操作的特點。對於C語言來說,一個整數在計算機內就是以二進位制的形式儲存的,所以沒有必要再將一個整數經過一系列的運算轉換為二進位制形式,只要將整數在記憶體中的二進位制表示輸出即可。
*程式說明與註釋
#include<stdio.h>
void printb(int,int);
void main()
{
intx;printf("Input number:");
scanf("%d",&x);
printf("numberof decimal form:%d\\n",x);
printf(" it\'sbinary form:");
printb(x,sizeof(int)*8);
putchar(\'\\n\');
}
void printb(int x,int n)
{
if(n>0)
{
putchar(\'0\'+((unsigned)(x&(1<<(n-1)))>>(n-1)));
printb(x,n-1);
}
}
*執行結果
輸入:8
輸出:
number of decimal form:8
it\'s bunaryform:0000000000001000
輸入:-8
輸出:number of decimal form:-8
it\'s binary form:1111111111111000
輸入:32767
輸出:number of decimal form:32767
it\'s binaryform:0111111111111111
輸入:-32768
輸出:number of decimal form:-32768
it\'s binaryform:1000000000000000
輸入:128
輸出:number of decimal form:128
it\'s binaryform:0000000010000000
11.打魚還是晒網
中國有句俗語叫“三天打魚兩天晒網”。某人從1990年1月1日起開始“三天打魚兩天晒網”,問這個人在以後的某一天中是“打魚”還是“晒網”。
*問題分析與演算法設計
根據題意可以將解題過程分為三步:
1)計算從1990年1月1日開始至指定日期共有多少天;
2)由於“打魚”和“晒網”的週期為5天,所以將計算出的天數用5去除;
3)根據餘數判斷他是在“打魚”還是在“晒網”;
若 餘數為1,2,3,則他是在“打魚”
否則 是在“晒網”
在這三步中,關鍵是第一步。求從1990年1月1日至指定日期有多少天,要判斷經歷年份中是否有閏年,二月為29天,平年為28天。閏年的方法可以用偽語句描述如下:
如果 ((年能被4除盡 且 不能被100除盡)或 能被400除盡)
則 該年是閏年;
否則 不是閏年。
C語言中判斷能否整除可以使用求餘運算(即求模)
*程式與程式註釋
#include<stdio.h>
int days(struct date day);
struct date{
int year;
int month;
int day;
};
void main()
{
struct datetoday,term;
intyearday,year,day;
printf("Enteryear/month/day:");
scanf("%d%d%d",&today.year,&today.month,&today.day);
term.month=12;
term.day=31;
for(yearday=0,year=1990;year<today.year;year++)
{
term.year=year;
yearday+=days(term);
}
yearday+=days(today);
day=yearday%5;
if(day>0&&day<4)printf("he was fishing at that day.\\n");
elseprintf("He was sleeping at that day.\\n");
}
int days(struct date day)
{
static intday_tab[2][13]=
{{0,31,28,31,30,31,30,31,31,30,31,30,31,},
{0,31,29,31,30,31,30,31,31,30,31,30,31,},
};
int i,lp;
lp=day.year%4==0&&day.year%100!=0||day.year%400==0;
for(i=1;i<day.month;i++)
day.day+=day_tab[lp];
return day.day;
}
*執行結果
Enteryear/month/day:1991 10 25
Hewas fishing at day.
Enteryear/month/day:1992 10 25
Hewas sleeping at day.
Enteryear/month/day:1993 10 25
Hewas sleeping at day
--------------------------------------------------------------------------------
12.抓交通肇事犯
一輛卡車違反交通規則,撞人後逃跑。現場有三人目擊事件,但都沒有記住車號,只記下車號的一些特徵。甲說:牌照的前兩位數字是相同的;乙說:牌照的後兩位數字是相同的,但與前兩位不同;丙是數學家,他說:四位的車號剛好是一個整數的平方。請根據以上線索求出車號。
*問題分析與演算法設計
按照題目的要求造出一個前兩位數相同、後兩位數相同且相互間又不同的整數,然後判斷該整數是否是另一個整數的平方。
*程式與程式註釋
#include<stdio.h>
#include<math.h>
void main()
{
int i,j,k,c;
for(i=1;i<=9;i++)
for(j=0;j<=9;j++)
if(i!=j)
{
k=i*1000+i*100+j*10+j;
for(c=31;c*c<k;c++);
if(c*c==k)printf("Lorry--No. is %d.\\n",k);
}
}
*執行結果
Lorry _No.is 7744
13.該存多少錢
假設銀行一年整存零取的月息為0.63%。現在某人手中有一筆錢,他打算在今後的五年中的年底取出1000元,到第五年時剛好取完,請算出他存錢時應存入多少。
*問題分析與演算法設計
分析存錢和取錢的過程,可以採用倒推的方法。若第五年年底連本帶息要取1000元,則要先求出第五年年初銀行存款的錢數:
第五年初存款=1000/(1+12*0.0063)
依次類推可以求出第四年、第三年......的年初銀行存款的錢數:
第四年年初存款=(第五年年初存款+1000)/(1+12*0.0063)
第三年年初存款=(第四年年初存款+1000)/(1+12*0.0063)
第二年年初存款=(第三年年初存款+1000)/(1+12*0.0063)
第一年年初存款=(第二年年初存款+1000)/(1+12*0.0063)
通過以上過程就可以很容易地求出第一年年初要存入多少錢。
*程式與程式註釋
#include<stdio.h>
void main()
{
int i;
float total=0;
for(i=0;i<5;i++)
total=(total+1000)/(1+0.0063*12);
printf("Hemust save %.2f at first.\\n",total);
}
*執行結果
He must save4039.44 at first
14.怎樣存錢利最大
假設銀行整存整取存款不同期限的月息利率分別為:
0.63% 期限=1年
0.66% 期限=2年
0.69% 期限=3年
0.75% 期限=5年
0.84% 期限=8年
利息=本金*月息利率*12*存款年限。
現在某人手中有2000元錢,請通過計算選擇一種存錢方案,使得錢存入銀行20年後得到的利息最多(假定銀行對超過存款期限的那一部分時間不付利息)。
*問題分析與演算法
為了得到最多的利息,存入銀行的錢應在到期時馬上取出來,然後立刻將原來的本金和利息加起來再作為新的本金存入銀行,這樣不斷地滾動直到滿20年為止,由於存款的利率不同,所以不同的存款方法(年限)存20年得到的利息是不一樣的。
分析題意,設2000元存20年,其中1年存i1次,2年存i2次,3年存i3次,5年存i5次,8年存i8次,則到期時存款人應得到的本利合計為:
2000*(1+rate1)i1*(1+rate2)i2*(1+rate3)i3*(1+rate5)i5*(1+rate8)i8
其中rateN為對應存款年限的利率。根據題意還可得到以下限制條件:
0<=i8<=2
0<=i5<=(20-8*i8)/5
0<=i3<=(20-8*i8-5*i5)/3
0<=i2<=(20-8*i8-5*i5-3*i3)/2
0<=i1=20-8*i8-5*i5-3*i3-2*i2
可以用窮舉法窮舉所有的i8、i5、i3、i2和i1的組合,代入求本利的公式計算出最大值,就是最佳存款方案。
*程式與程式註釋
#include<stdio.h>
#include<math.h>
void main()
{
inti8,i5,i3,i2,i1,n8,n5,n3,n2,n1;
float max=0,term;
for(i8=0;i8<3;i8++)
for(i5=0;i5<=(20-8*i8)/5;i5++)
for(i3=0;i3<=(20-8*i8-5*i5)/3;i3++)
for(i2=0;i2<=(20-8*i8-5*i5-3*i3)/2;i2++)
{
i1=20-8*i8-5*i5-3*i3-2*i2;
term=2000.0*pow((double)(1+0.0063*12),(double)i1)
*pow((double)(1+2*0.0063*12),(double)i2)
*pow((double)(1+3*0.0069*12),(double)i3)
*pow((double)(1+5*0.0075*12),(double)i5)
*pow((double)(1+8*0.0084*12),(double)i8);
if(term>max)
{
max=term;n1=i1;n2=i2;n3=i3;n5=i5;n8=i8;
}
}
printf("Formaxinum profit,he should so save his money in a bank:\\n");
printf(" madefixed deposit for 8 year: %d times\\n",n8);
printf(" madefixed deposit for 5 year: %d times\\n",n5);
printf(" madefixed deposit for 3 year: %d times\\n",n3);
printf(" madefixed deposit for 2 year: %d times\\n",n2);
printf(" madefixed deposit for 1 year: %d times\\n",n1);
printf(" Toal:%.2f\\n",max);
}
*執行結果
For maxinum profit,he should so save hismoney in a bank:
made fixed depositfor 8 year: 0times
made fixed depositfor 5 year: 4times
made fixed depositfor 3 year: 0times
made fixed depositfor 2 year: 0times
made fixed depositfor 1 year: 0times
Total:8841.01
可見最佳的存款方案為連續四次存5年期。
*思考題
某單位對職工出售住房,每套為2萬元。買房付款的方法是:
一次交清,優惠20%
從第一年開始,每年年初分期付款:
5年交清,優惠50%;
10年交清,優惠10%;
20年交清,沒有優惠。
現在有人手中正好有2萬元,若假定在今後20年中物價和銀行利率均保持不變,問他應當選擇哪種付款方式可以使應付的錢最少?
--------------------------------------------------------------------------------
15.捕魚和分魚
A、B、C、D、E五個人在某天夜裡合夥去捕魚,到第二天凌晨時都疲憊不堪,於是各自找地方睡覺。日上三杆,A第一個醒來,他將魚分為五份,把多餘的一條魚扔掉,拿走自己的一份。B第二個醒來,也將魚分為五份,把多餘的一條魚扔掉,保持走自己的一份。C、D、E依次醒來,也按同樣的方法拿走魚。問他們合夥至少捕了多少條魚?
*問題分析與演算法設計
根據題意,總計將所有的魚進行了五次平均分配,每次分配時的策略是相同的,即扔掉一條魚後剩下的魚正好分成五份,然後拿走自己的一份,餘下其它的四份。
假定魚的總數為X,則X可以按照題目的要求進行五次分配:X-1後可被5整除,餘下的魚為4*(X-1)、5。若X滿足上述要求,則X就是題目的解。
*程式與程式註釋
#include<stdio.h>
void main()
{
intn,i,x,flag=1;
for(n=6;flag;n++)
{
for(x=n,i=1&&flag;i<=5;i++)
if((x-1)%5==0)x=4*(x-1)/5;
else flag=0;
if(flag)break;
elseflag=1;
}
printf("Totalnumber of fish catched=%d\\n",n);
}
*執行結果
Total number of fishcatched = 3121
*問題的進一步討論
程式採用試探法,試探的初值為6,每次試探的步長為1。這是過分保守的做法。可以在進一步分析題目的基礎上修改此值,增大試探的步長值,以減少試探次數。
*思考題
請使用其它的方法求解本題
16.出售金魚
買賣提將養的一缸金魚分五次出售系統上一次賣出全部的一半加二分之一條;第二次賣出餘下的三分之一加三分之一條;第三次賣出餘下的四分之一加四分之一條;第四次賣出餘下的五分之一加五分之一條;最後賣出餘下的11條。問原來的魚缸中共有幾條金魚?
*題目分析與演算法設計
題目中所有的魚是分五次出售的,每次賣出的策略相同;第j次賣剩下的(j+1)分之一再加1/(j+1)條。第五次將第四次餘下的11條全賣了。
假定第j次魚的總數為X,則第j次留下:
x-(x+1)/(j+1)
當第四次出售完畢時,應該剩下11條。若X滿足上述要求,則X就是題目的解。
應當注意的是:"(x+1)/(j+1)"應滿足整除條件。試探X的初值可以從23開始,試探的步長為2,因為X的值一定為奇數。
*程式說明與註釋
#include<stdio.h>
void main()
{
inti,j,n=0,x;
for(i=23;n==0;i+=2)
{
for(j=1,x=i;j<=4&&x>=11;j++)
if((x+1)%(j+1)==0)
x-=(x+1)/(j+1);
else{x=0;break;}
if(j==5&&x==11)
{
printf("Thereare %d fishes atfirst.\\n",i);
n=1;
}
}
}
*執行結果
There are 59 fishesat first.
*思考題
日本著名數學遊戲專家中村義作教授提出這樣一個問題:父親將2520個桔子分給六個兒子。分完後父親說:“老大將分給你的桔子的1/8給老二;老二拿到後連同原先的桔子分1/7給老三;老三拿到後連同原先的桔子分1/6給老四;老四拿到後連同原先的桔子分1/5給老五;老五拿到後連同原先的桔子分1/4給老六;老六拿到後連同原先的桔子分1/3給老大”。結果大家手中的桔子正好一樣多。問六兄弟原來手中各有多少桔子?
1.7 分數四則運算
對輸入的兩個分數進行+、-、*、/四則運算,輸出分數結果。
演算法分析如下:
對分數b/a與d/c,不管哪一種運算,其運算結果均為y/x形式。對結果y/x進行化簡,約去分子分母的公因數:試用i(i=1,...,y)對y,x進行試商,若能同時整除y,x,則y,x同時約去公因數i,最後列印約簡的分數。
程式程式碼如下:
#include<stdio.h>
void main()
{
long inta,b,c,d,i,x,y,z;
char op;
printf("兩分數b/a,d/c作+,-,*,/四則運算,結果為分數。\\n");
printf("請輸入分數運算式。\\n");
scanf("%ld/%ld%c%ld/%ld",&b,&a,&op,&d,&c);
if(a==0||c==0){printf("分母為0輸入錯誤!");exit(0);}
if(op==\'+\'){y=b*c+d*a;x=a*c;}
if(op==\'-\'){y=b*c-d*a,x=a*c;}
if(op==\'*\'){y=b*d;x=a*c;}
if(op==\'/\'){y=b/c;x=a/d;}
z=x;
if(x>y) z=y;
i=z;
while(i>1)
{
if(x%i==0&&y%i==0){x=x/i;y=y/i;continue;}
i--;
}
printf("%ld/%ld%c%ld/%ld=%ld/%ld.\\n",b,a,op,d,c,y,x);
}
--------------------------------------------------------------------------------
17.平分七筐魚
甲、乙、丙三位魚夫出海打魚,他們隨船帶了21只籮筐。當晚返航時,他們發現有七筐裝滿了魚,還有七筐裝了半筐魚,另外七筐則是空的,由於他們沒有秤,只好通過目測認為七個滿筐魚的重量是相等的,7個半筐魚的重量是相等的。在不將魚倒出來的前提下,怎樣將魚和筐平分為三份?
*問題分析與演算法設計
根據題意可以知道:每個人應分得七個籮筐,其中有3.5筐魚。採用一個3*3的陣列a來表示三個人分到的東西。其中每個人對應陣列a的一行,陣列的第0列放分到的魚的整筐數,陣列的第1列放分到的半筐數,陣列的第2列放分到的空筐數。由題目可以推出:
。陣列的每行或每列的元素之和都為7;
。對陣列的行來說,滿筐數加半筐數=3.5;
。每個人所得的滿筐數不能超過3筐;
。每個人都必須至少有1 個半筐,且半筐數一定為奇數
對於找到的某種分魚方案,三個人誰拿哪一份都是相同的,為了避免出現重複的分配方案,可以規定:第二個人的滿筐數等於第一個人的滿筐數;第二個人的半筐數大於等於第一個人的半筐數。
*程式與程式註釋
#include<stdio.h>
int a[3][3],count;
void main()
{
int i,j,k,m,n,flag;
printf("Itexists possible distribtion plans:\\n");
for(i=0;i<=3;i++)
{
a[0][0]=i;
for(j=i;j<=7-i&&j<=3;j++)
{
a[1][0]=j;
if((a[2][0]=7-j-a[0][0])>3)continue;
if(a[2][0]<a[1][0])break;
for(k=1;k<=5;k+=2)
{
a[0][1]=k;
for(m=1;m<7-k;m+=2)
{
a[1][1]=m;
a[2][1]=7-k-m;
for(flag=1,n=0;flag&&n<3;n++)
if(a[n][0]+a[n][1]<7&&a[n][0]*2+a[n][1]==7)
a[n][2]=7-a[n][0]-a[n][1];
elseflag=0;
if(flag)
{
printf("No.%d Fullbasket Semi--basket Empty\\n",++count);
for(n=0;n<3;n++)
printf(" fisher%c: %d %d %d\\n",
\'A\'+n,a[n][0],a[n][1],a[n][2]);
}
}
}
}
}
}
* 執行結果
It exists possible distribution plans:
No.1 Fullbasket Semi--basket Empty
fisherA: 1 5 1
fisherB: 3 1 3
fisherC: 3 1 3
No.2 Fullbasket Semi--basket Empty
fisherA: 2 3 2
fisherB: 2 3 2
fisherC: 3 1 3
*思考題
晏會上數學家出了一道難題:假定桌子上有三瓶啤酒,癬瓶子中的酒分給幾個人喝,但喝各瓶酒的人數是不一樣的。不過其中有一個人喝了每一瓶中的酒,且加起來剛好是一瓶,請問喝這三瓶酒的各有多少人?
(答案:喝三瓶酒的人數分別是2人、3人和6人)
18.有限5位數
個位數為6且能被3整除的五位數共有多少?
*題目分析與演算法設計
根據題意可知,滿足條件的五位數的選擇範圍是10006、10016。。。99996。可設基礎數i=1000,通過計算i*10+6即可得到欲選的數(i的變化範圍是1000~999),再判斷該數能否被3整除。
*程式說明與註釋
#include<stdio.h>
void main()
{
long inti;
intcount=0;
for(i=1000;i<9999;i++)
if(!((i*10+6)%3))
count++;
printf("count=%d\\n",count);
}
*執行結果
count=2999
*思考題
求100到1000之間有多少個其數字之和為5的整數。
(答案:104,113,122,131,140,203,212,221,230,302,311,320,401,410,500)
19. 8 除不盡的數
一個自然數被8除餘1,所得的商被8除也餘1,再將第二次的商被8除後餘7,最後得到一個商為a。又知這個自然數被17除餘4,所得的商被17除餘15,最後得到一個商是a的2倍。求這個自然數。
*題目分析與演算法設計
根據題意,可設最後的商為i(i從0開始取值),用逆推法可以列出關係式:
(((i*8+7)*8)+1)*8+1=((2*i*17)+15)*18+4
再用試探法求出商i的值。
*程式說明與註釋
#include<stdio.h>
void main()
{
int i;
for(i=0;;i++)
if(((i*8+7)*8+1)*8+1==(34*i+15)*17+4)
{
printf("Therequired number is: %d\\n",(34*i+15)*17+4);
break;
}
}
*執行結果
The required number is:199320.一個奇異的三位數
一個自然數的七進製表達式是一個三位數,而這個自然數的九進製表示也是一個三位數,且這兩個三位數的數碼正好相反,求這個三位數。
*題目分析與演算法設計
根據題意可知,七進位制和九進製表示的這全自然數的每一位一定小於7,可設其七進位制數形式為kji(i、j、k的取值分別為1~6),然後設其九進製表示形式為ijk。
*程式說明與註釋
#include<stdio.h>
void main()
{
int i,j,k;
for(i=1;i<7;i++)
for(j=0;j<7;j++)
for(k=1;k<7;k++)
if(i*9*9+j*9+k==i+j*7+k*7*7)
{
printf("Thespecial number with 3 digits is:");
printf("%d%d%d(7)=%d%d%d(9)=%d(10)\\n",k,j,i,i,j,k,i*9*9+j*9+k);
}
}
*執行結果
The special numberwith 3 digits is:503(7)=305(9)=248(10)
--------------------------------------------------------------------------------
21.4位反序數
設N是一個四位數,它的9倍恰好是其反序數,求N。反序數就是將整數的數字倒過來形成的整數。例如:1234的反序數是4321。
*題目分析與演算法設計
可設整數N的千、百、十、個位為i、j、k、l,其取值均為0~9,則滿足關係式:
(i*103+j*102+10*k+l)*9=(l*103+k*102+10*j+i)
的i、j、k、l即構成N。
*程式說明與註釋
#include<stdio.h>
void main()
{
int i;
for(i=1002;i<1111;i++)
if(i%10*1000+i/10%10*100+i/100%10*10+i/1000==i*9)
printf("Thenumber satisfied stats condition is: %d\\n",i);
}
*執行結果
The numbersatisfied states condition is:1089
22.求車速
一輛以固定速度行駛的汽車,司機在上午10點看到里程錶上的讀數是一個對稱數(即這個數從左向右讀和從右向左讀是完全一樣的),為95859。兩小時後里程錶上出現了一個新的對稱數。問該車的速度是多少?新的對稱數是多少?
*題目分析與演算法設計
根據題意,設所求對稱數為i,其初值為95589,對其依次遞增取值,將i值的每一位分解後與其對稱位置上的數進行比較,若每個對稱位置上的數皆相等,則可判定i即為所求的對稱數。
*程式說明與註釋
#include<stdio.h>
void main()
{
intt,a[5];
long int k,i;
for(i=95860;;i++)
{
for(t=0,k=100000;k>=10;t++)
{
a[t]=(i%k)/(k/10);
k/=10;
}
if((a[0]==a[4])&&(a[1]==a[3]))
{
printf("Thenew symmetrical number kelometers is:%d%d%d%d%d\\n",
a[0],a[1],a[2],a[3],a[4]);
printf("Thevelocity of the car is: %.2f\\n",(i-95859)/2.0);
break;
}
}
}
*執行結果
The new symmetricalnumber kelometers is:95959.
The velocity of thecar is:50.00
*思考題
將一個數的數碼倒過來所得到的新數叫原數的反序數。如果一個數等於它的反序數,則稱它為對稱數。求不超過1993的最大的二進位制的對稱數
23.阿姆斯特朗數
如果一個正整數等於其各個數字的立方和,則稱該數為阿姆斯特朗數(亦稱為自戀性數)。
如 407=43+03+73就是一個阿姆斯特朗數。試程式設計求1000以內的所有阿姆斯特朗數。
*題目分析與演算法設計
可採用窮舉法,依次取1000以內的各數(設為i),將i的各位數字分解後,據阿姆斯特朗數的性質進行計算和判斷。
*程式說明與註釋
#include<stdio.h>
void main()
{
int i,t,k,a[3];
printf("Thereare follwing Armstrong number smaller than 1000:\\n");
for(i=2;i<1000;i++)
{
for(t=0,k=1000;k>=10;t++)
{
a[t]=(i%k)/(k/10);
k/=10;
}
if(a[0]*a[0]*a[0]+a[1]*a[1]*a[1]+a[2]*a[2]*a[2]==i)
printf("%5d",i);
}
printf("\\n");
}
*執行結果
There are followingArmstrong number smaller than 1000:
153 370 371 407
--------------------------------------------------------------------------------
24.完全數
如果一個數恰好等於它的因子之和,則稱該數為“完全數”。
*題目分析與演算法設計
根據完全數的定義,先計算所選取的整數a(a的取值1~1000)的因子,將各因子累加於m,若m等於a,則可確認a為完全數。
*程式說明與註釋
#include<stdio.h>
void main()
{
int a,i,m;
printf("Thereare following perfect numbers smaller than 1000:\\n");
for(a=1;a<1000;a++)
{
for(m=0,i=1;i<=a/2;i++)
if(!(a%i))m+=i;
if(m==a)
printf("%4d",a);
}
printf("\\n");
}
*執行結果
TThere arefollowing perfect numbers smaller than 1000:
6 28 496
26.親密數
如果整數A的全部因子(包括1,不包括A本身)之和等於B;且整數B的全部因子(包括1,不包括B本身)之和等於A,則將整數A和B稱為親密數。求3000以內的全部親密數。
*題目分析與演算法設計
按照親密數定義,要判斷數a是否有親密數,只要計算出a的全部因子的累加和為b,再計算b的全部因子的累加和為n,若n等於a則可判定a和b是親密數。計算數a的各因子的演算法:
用a依次對i(i=1~a/2)進行模運算,若模運算結果等於0,則i為a的一個因子;否則i就不是a的因子。
*程式說明與註釋
#include<stdio.h>
void main()
{
int a,i,b,n;
printf("Thereare following friendly--numbers pair smaller than 3000:\\n");
for(a=1;a<3000;a++)
{
for(b=0,i=1;i<=a/2;i++)
if(!(a%i))b+=i;
for(n=0,i=1;i<=b/2;i++)
if(!(b%i))n+=i;
if(n==a&&a<b)
printf("%4d..%4d ",a,b);
}
}
*執行結果
There are followingfriendly--numbers pair smaller than 3000:
220.. 284 1184..1210 2620.. 2924
27.自守數
自守數是指一個數的平方的尾數等於該數自身的自然數。例如:
252=625 762=5776 93762=87909376
請求出200000以內的自守數
*題目分析與演算法設計
若採用“求出一個數的平方後再擷取最後相應位數”的方法顯然是不可取的,因為計算機無法表示過大的整數。
分析手工方式下整數平方(乘法)的計算過程,以376為例:
376 被乘數
X 376 乘數
----------
2256 第一個部分積=被乘數*乘數的倒數第一位
2632 第二個部分積=被乘數*乘數的倒數第二位
1128 第三個部分積=被乘數*乘數的倒數第三位
----------
141376 積
本問題所關心的是積的最後三位。分析產生積的後三位的過程,可以看出,在每一次的部分積中,並不是它的每一位都會對積的後三位產生影響。總結規律可以得到:在三位數乘法中,對積的後三位產生影響的部分積分別為:
第一個部分積中:被乘數最後三位*乘數的倒數第一位
第二個部分積中:被乘數最後二位*乘數的倒數第二位
第三個部分積中:被乘數最後一位*乘數的倒數第三位
將以上的部分積的後三位求和後擷取後三位就是三位數乘積的後三位。這樣的規律可以推廣到同樣問題的不同位數乘積。
按照手工計算的過程可以設計演算法編寫程式。
*程式說明與註釋
#include<stdio.h>
void main()
{
longmul,number,k,ll,kk;
printf("Itexists following automorphic nmbers small than 200000:\\n");
for(number=0;number<200000;number++)
{
for(mul=number,k=1;(mul/=10)>0;k*=10);
kk=k*10;
mul=0;
ll=10;
while(k>0)
{
mul=(mul+(number%(k*10))*(number%ll-number%(ll/10)))%kk;
k/=10;
ll*=10;
}
if(number==mul)
printf("%ld ",number);
}
}
*執行結果
It exsts followingautomorphic numbners smaller than 200000:
0 1 5 6 25 76 376 625 9376 90625 109376
28.迴文數
列印所有不超過n(取n<256) 的其平方具有對稱性質的數(也稱迴文數)。
*題目分析與演算法設計
對於要判斷的數n,計算出其平方後(存於a),將a的每一位進行分解,再按a的從低到高的順序將其恢復成一個數k(如n=13,則a=169且k=961),若a等於k則可判定n為回亠數。
*程式說明與註釋
#include<stdio.h>
void main()
{
intm[16],n,i,t,count=0;
long unsigned a,k;
printf("No. number it\'ssquare(palindrome)\\n");
for(n=1;n<256;n++)
{
k=0;t=1;a=n*n;
for(i=1;a!=0;i++)
{
m=a%10;
a/=10;
}
for(;i>1;i--)
{
k+=m[i-1]*t;
t*=10;
}
if(k==n*n)
printf("%2d%10d%10d\\n",++count,n,n*n);
}
}
*執行結果
No. number it\'ssquare(palindrome)
1 1 1
2 2 4
3 3 9
4 11 121
5 22 484
6 26 676
7 101 10201
8 111 12321
9 121 14641
--------------------------------------------------------------------------------
29.求具有abcd=(ab+cd)2性質的四位數
3025這個數具有一種獨特的性質:將它平分為二段,即30和25,使之相加後求平方,即(30+25)2,恰好等於3025本身。請求出具有這樣性質的全部四位數。
*題目分析與演算法設計
具有這種性質的四位數沒有分佈規律,可以採用窮舉法,對所有四位數進行判斷,從而篩選出符合這種性質的四位數。具體演算法實現,可任取一個四位數,將其截為兩部分,前兩位為a,後兩位為b,然後套用公式計算並判斷。
*程式說明與註釋
#include<stdio.h>
void main()
{
int n,a,b;
printf("Thereare following number with 4 digits satisfied condition\\n");
for(n=1000;n<10000;n++)
{
a=n/100;
b=n%100;
if((a+b)*(a+b)==n)
printf("%d ",n);
}
}
*執行結果
There are followingnumbers with 4 digits satisfied condition:
2025 3025 9801
30.求素數
求素數表中1~1000之間的所有素數
*問題分析與演算法設計
素數就是僅能衩1和它自身整除的整數。判定一個整數n是否為素數就是要判定整數n能否被除1和它自身之外的任意整數整除,若都不能整除,則n為素數。
程式設計時i可以從2開始,到該整數n的1/2為止,用i依次去除需要判定的整數,只要存在可以整除該數的情況,即可確定要判斷的整數不是素數,否則是素數。
*程式與程式註釋
#include<stdio.h>
void main()
{
intn1,nm,i,j,flag,count=0;
do{
printf("InputSTART and END=?");
scanf("%d%d",&n1,&nm);
}while(!(n1>0&&n1<nm));
printf("...........PRIMETABLE(%d--%d)............\\n",n1,nm);
if(n1==1||n1==2)
{
printf("%4d",2);
n1=3;count++;
}
for(i=n1;i<=nm;i++)
{
if(!(i%2))continue;
for(flag=1,j=3;flag&&j<i/2;j+=2)
if(!(i%j))flag=0;
if(flag)printf(++count%15?"%4d":"%4d\\n",i);
}
}
31.歌德巴赫猜想
驗證:2000以內的正偶數都能夠分解為兩個素數之和(即驗證歌德巴赫猜想對2000以內的正偶數成立)。
*問題分析與演算法設計
為了驗證歌德巴赫猜想對2000以內的正偶數都是成立的,要將整數分解為兩部分,然後判斷出分解出的兩個整數是否均為素數。若是,則滿足題意;否則重新進行分解和判斷。
程式中對判斷是否為素數的演算法進行了改進,對整數判斷“用從2開始到該整數的一半”改為“2開始到該整數的平方根”。原因何在請自行分析。
*程式與程式註釋
#include<stdio.h>
#include<math.h>
int fflag(int n);
void main()
{
int i,n;
for(i=4;i<=2000;i+=2)
{
for(n=2;n<i;n++)
if(fflag(n))
if(fflag(i-n))
{
printf("%14d=%d+%d\\n",i,n,i-n);
break;
}
if(n==i) printf("error%d\\n",i);
}
}
int fflag(inti)
{
int j;
if(i<=1)return0;
if(i==2)return 1;
if(!(i%2))return0;
for(j=3;j<=(int)(sqrt((double)i)+1);j+=2)
if(!(i%j))return0;
return1;
}
--------------------------------------------------------------------------------
32.要發就發
“1898--要發就發”。請將不超過1993的所有素數從小到大排成第一行,第二行上的每個素數都等於它右肩上的素數之差。程式設計求出:第二行數中是否存在這樣的若干個連續的整數,它們的和恰好是1898?假好存在的話,又有幾種這樣的情況?
第一行:2 3 5 7 11 13 17......1979 1987 1993
第二行:1 2 2 4 2 4...... 8 6
*問題分析與演算法設計:
首先從數學上分析該問題:
假設第一行中的素數為n[1]、n[2]、n[3]....n、...第二行中的差值為m[1]、m[2]、m[3]...m[j]...。其中m[j]為:
m[j]=n[j+1]-n[j]。
則第二行連續N個數的和為:
SUM=m[1]+m[2]+m[3]+...+m[j]
=(n[2]-n[1])+(n[3]-n[2])+(n[4]-n[3])+...+(n[j+1]-n[j])
=n[j+1]-n[1]
由此題目就變成了:在不超過1993的所有素數中是否存在這樣兩個素數,它們的差恰好是1898。若存在,則第二行中必有所需整數序列,其和恰為1898,。
對等價問題的求解是比較簡單的。
由分析可知,在素數序列中不必包含2,因為任意素數與2的差一定為奇數,所以不必考慮。
*程式與程式註釋:
#include<stdio.h>
#include<math.h>
#define NUM 320
intnumber[NUM];
int fflag(int i);
void main()
{
int i,j,count=0;
printf("thereare follwing primes sequences in first row:\\n");
for(j=0,i=3;i<=1993;i+=2)
if(fflag(i))number[j++]=i;
for(j--;number[j]>1898;j--)
{
for(i=0;number[j]-number>1898;i++);
if(number[j]-number==1898)
printf("(%d).%3d,.....,%d\\n",++count,number,number[j]);
}
}
int fflag(int i)
{
int j;