⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 04.txt

📁 CC++语言程序百例精解 非常经典的C
💻 TXT
📖 第 1 页 / 共 2 页
字号:
if(k%2!=0&&k!=5&&num(i)) /*若可逆素数的第一位不是偶数或5*/
{
number[count][0]=i; /*存入数组*/
process(count++); /*分解素数的各位数字*/
if(number[count-1][2]%2!=0&& /*若可逆素数满足放在矩阵第一行*/
number[count-1][3]%2!=0&& /*和最后一行的条件,记录可逆素数的*/
number[count-1][2]!=5&& /*下标,计数器加1*/
number[count-1][3]!=5)
select[selecount++]=count-1;
}
}
larray[0][lcount[0]++]=number[0][0]/100; /*临时数组的第一行存前二位*/
larray[1][lcount[1]++]=number[0][0]/10; /*临时数组的第二行存前三位*/
for(i=1;i<count;i++) /*将素数不重复的前二、三位存入临时数组中*/
{
if(larray[0][lcount[0]-1]!=number[i][0]/100)
larray[0][lcount[0]++]=number[i][0]/100;
if(larray[1][lcount[1]-1]!=number[i][0]/10)
larray[1][lcount[1]++]=number[i][0]/10;
}
for(i1=0;i1<selecount;i1++) /*在第一行允许的汇聚围内穷举*/
{
array[0][0]=select[i1]; /*取对应的素数下标*/
copy_num(0); /*复制分解的素数*/
for(array[1][0]=0;array[1][0]<count;array[1][0]++) /*穷举第二行*/
{
copy_num(1); /*复制分解的数字*/
if(!comp_num(2))
continue; /*若每列的前两位的组成与素数相矛盾,则试探下一个数*/
for(array[2][0]=0;array[2][0]<count;array[2][0]++) /*穷举第三行*/
{
copy_num(2); /*复制分解的数字*/
if(!comp_num(3))
continue; /*若每列的前三位的组成与素数相矛盾,则试探下一个数*/
for(i4=0;i4<selecount;i4++) /*在最后一行允许的范围内穷举*/
{
array[3][0]=select[i4];
copy_num(3); /*复制分解的数字*/
for(flag=1,i=1;flag&&i<=4;i++) /*判断每列是否可逆素数*/
if(!find1(i))flag=0;
if(flag&&find2()) /*判断对角线是否为可逆素数*/
{ printf("No.%d\n",++cc); p_array(); } /*输出幻方矩阵*/
}
}
}
}
}

int num(int number) /*判断是否可逆素数*/
{
int j;
if(!ok(number)) return 0;
for(j=0;number>0;number/=10) /*将素数变为反序数*/
j=j*10+number%10;
if(!ok(j)) return 0; /*判断反序数是否为素数*/
return 1;
}

int ok(int number) /*判断是否为素数*/
{
int i,j;
if(number%2==0) return 0;
j=sqrt((double)number)+1;
for(i=3;i<=j;i+=2)
if(number%i==0) return 0;
return 1;
}

void process(int i) /*将第i个整数分解为数字并存入数组*/
{
int j,num;
num=number[i][0];
for(j=4;j>=1;j–,num/=10)
number[i][j]=num%10;
}

void copy_num(int i) /*将array[i][0]指向的素数的各位数字复制到array[i]中*/
{
int j;
for(j=1;j<=4;j++)
array[i][j]=number[array[i][0>[j];
}

int comp_num(int n) /*判断array中每列的前n位是否与可逆素数允许的前n位矛盾*/
{
static int ii; /*用内部静态变量保存前一次查找到的元素下标*/
static int jj; /*ii:前一次查找前二位的下标,jj:前一次查找前三位的下标*/
int i,num,k,*p; /*p:指向对应的要使用的前一次下标ii或jj*/
int *pcount; /*pcount:指向要使用的临时数组数量的计数器*/
switch(n){ /*根据n的值选择对应的一组控制变量*/
case 2:pcount=&lcount[0];p=&ii;break;
case 3:pcount=&lcount[1];p=&jj;break;
default:return 0;
}
for(i=1;i<=4;i++) /*对四列分别进行处理*/
{
for(num=0,k=0;k<n;k++) /*计算前n位数字代表的数值*/
num=num*10+array[k][i];
if(num<=larray[n-2][*p]) /*与前一次最后查找到的元素进行比较*/
for(;*p>=0&&num<larray[n-2][*p];(*p)–);/*若前次查找到的元素大,则向前找*/
else
for(;p<pcount&&num>larray[n-2][*p];(*p)++); /*否则向后找*/
if(*p<0||*p>=*pcount)
{
*p=0; return 0;
}
if(num!=larray[n-2][*p])
return 0; /*前n位不是可逆素数允许的值则返回0*/
}
return 1;
}

int find1(int i) /*判断列方向是否是可逆素数*/
{
int num,j;
for(num=0,j=0;j<4;j++)
num=num*10+array[j][i];
return find0(num);
}

int find2(void) /*判断对角线方向是否是可逆素数*/
{
int num1,num2,i,j;
for(num1=0,j=0;j<4;j++)
num1=num1*10+array[j][j+1];
for(num2=0,j=0,i=4;j<4;j++,i–)
num2=num2*10+array[j][i];
if(find0(num1)) return(find0(num2));
else return 0;
}

int find0(int num) /*查找是否为满足要求的可逆素数*/
{
static int j;
if(num<=number[j][0])for(;j>=0&&num<number[j][0];j–);
else for(;j<count&&num>number[j][0];j++);
if(j<0||j>=count){ j=0;return 0; }
if(num==number[j][0]) return 1;
else return 0;
}

void p_array(void) /*输出矩阵*/
{
int i,j;
for(i=0;i<4;i++)
{
for(j=1;j<=4;j++) printf("%d ",array[i][j]);
printf("\n");
}
}

*问题的进一步讨论
程序中大量技巧是用于尽早发现矛盾,减少循环次数,缩短运行时间。从实际效果看是相当不错的。但目前的程序仍然可以进一步优化。
当第四行设定了前三行后,尚未设定的行就没必要再使用穷举的方法,因为列方向设定好的三位数字已经限制了最后一个数字可能的取值,在可逆数中找出前三位数字与设定好的三位数字相同的素数。这些素数就是在这一列前面已设定好的三位数字的限制条件下可能的取值。此时每一列上只有不超过四个可能的取值。找出全部各列可能的取值(可能的四位可逆素数),求出它们的交集。若交集为空,即没有共同的可能取值,则列间数据相互矛盾否满足则将交集中的数据填入矩阵中就是题目的一个解。
算法可再进一步优化。先穷举一、二和四列的数据,然后用上面的算法来确定第三行的值,这样可进一步缩小穷举的范围,提高运行效率。
分析输出的结果。可以看出本题的基本解只有17种,每个解可通过旋转与反射获得同构的其它7个解,可以进一步改进程序,只输出17个基本解。

*思考题
用1到16构成一个四阶幻方,要求任意相邻两个方格中的数字之和均为素数。

36.百钱百鸡问题

中国古代数学家张丘建在他的《算经》中提出了著名的“百钱买百鸡问题”:鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一,百钱买百鸡,问翁、母、雏各几何?

*问题分析与算法设计
设鸡翁、鸡母、鸡雏的个数分别为x,y,z,题意给定共100钱要买百鸡,若全买公鸡最多买20只,显然x的值在0~20之间;同理,y的取值范围在0~33之间,可得到下面的不定方程:
5x+3y+z/3=100
x+y+z=100
所以此问题可归结为求这个不定方程的整数解。
由程序设计实现不定方程的求解与手工计算不同。在分析确定方程中未知数变化范围的前提下,可通过对未知数可变范围的穷举,验证方程在什么情况下成立,从而得到相应的解。

*程序说明与注释
#include<stdio.h>
int main()
{
int x,y,z,j=0;
printf("Folleing are possible plans to buy 100 fowls with 100 Yuan.\n");
for(x=0;x<=20;x++) /*外层循环控制鸡翁数*/
for(y=0;y<=33;y++) /*内层循环控制鸡母数y在0~33变化*/
{
z=100-x-y; /*内外层循环控制下,鸡雏数z的值受x,y的值的制约*/
if(z%3==0&&5*x+3*y+z/3==100)
/*验证取z值的合理性及得到一组解的合理性*/
printf("%2d:cock=%2d hen=%2d chicken=%2d\n",++j,x,y,z);
}
}

*运行结果
Follwing are possible plans to buy 100 fowls with 100 Yuan.
1:cock=0 hen=25 chicken=75
2:cock=4 hen=18 chicken=78
3:cock=8 hen=11 chicken=81
4:cock=12 hen=4 chicken=84

*问题的进一步讨论
这类求解不定方程总理的实现,各层循环的控制变量直接与方程未知数有关,且采用对未知数的取值范上穷举和组合的方法来复盖可能得到的全部各组解。能否根据题意更合理的设置循环控制条件来减少这种穷举和组合的次数,提高程序的执行效率,请读者考虑

37.爱因斯坦的数学题

爱因斯坦出了一道这样的数学题:有一条长阶梯,若每步跨2阶,则最最后剩一阶,若每步跨3 阶,则最后剩2阶,若每步跨5阶,则最后剩4阶,若每步跨6阶则最后剩5阶。只有每次跨7阶,最后才正好一阶不剩。请问这条阶梯共有多少阶?

*问题分析与算法设计
根据题意,阶梯数满足下面一组同余式:
x≡1 (mod2)
x≡2 (mod3)
x≡4 (mod5)
x≡5 (mod6)
x≡0 (mod7)

*程序说明与注释
#include<stdio.h>
int main()
{
int i=1; /*i为所设的阶梯数*/
while(!((i%2==1)&&(i%3==2)&&(i%5==4)&&(i%6==5)&&(i%7==0)))
++i; /*满足一组同余式的判别*/
printf("Staris_number=%d\n",i);
}

*运行结果
Staris_number=119

*问题的进一步讨论
此题算法还可考虑求1、2、4、5的最小公倍数n,然后判t(t为n-1)≡0(mod7)是否成立,若不成立则t=t+n,再进行判别,直至选出满足条件的t值。请自行编写程序实现

 38.换分币

用一元人民币兑换成1分、2分和5分硬币,共有多少种不同的兑换方法。

*问题分析与算法设计
根据题意设i,j,k分别为兑换的1分、2分、5分硬币所具有的钱数(分),则i,j,k的值应满足:
i+j+k=100

*程序说明与注释
#include<stdio.h>
int main()
{
int i,j,k,count=1;
printf("There are follwing small exchange plans for 1 Yuan note:\n");
for(i=0;i<=100;i++) /*i为1分硬币钱数,可取值0,1,2…,100*/
for(j=0;j<=100-i;j+=2) /*j为2分硬币钱数,可取0值,2,4,…,100*/
for(k=0;k<=100-i-2*j;k+=5) /*k为5分硬币钱数*/
if(i+j+k==100)
printf(count%4?"%d:1*%d+2*%d+5*%d\t":"%d:1*%d+2*%d+5*%d\n",count++,i,j/2,k/5);
}

 

39.年龄几何

张三、李四、王五、刘六的年龄成一等差数列,他们四人的年龄相加是26,相乘是880,求以他们的年龄为前4项的等差数列的前20项。

*问题分析与算法设计
设数列的首项为a,则前4项之和为"4*n+6*a",前4 项之积为"n*(n+a)*(n+a+a)*(n+a+a+a)"。同时"1<=a<=4","1<=n<=6"。可采用穷举法求出此数列。

*程序说明与注释
#include<stdio.h>
int main()
{
int n,a,i;
printf("The series with equal difference are:\n");
for(n=1;n<=6;n++) /*公差n取值为1~6*/
for(a=1;a<=4;a++) /*首项a取值为1~4*/
if(4*n+6*a==26&&n*(n+a)*(n+a+a)*(n+a+a+a)==880) /*判断结果*/
for(i=0;i<20;i++)
printf("%d ",n+i*a); /*输出前20项*/
}

*运行结果
The series with equal difference are:
2 5 8 11 14 17 20 23 26 29 32 35 38 41 44 47 50 53 56 59

40.三色球问题

若一个口袋中放有12个球,其中有3个红的。3个白的和6个黒的,问从中任取8个共有多少种不同的颜色搭配?

*问题分析与算法设计
设任取的红球个数为i,白球个数为j,则黒球个数为8-i-j,根据题意红球和白球个数的取值范围是0~3,在红球和白球个数确定的条件下,黒球个数取值应为8-i-j<=6。

*程序说明与注释
#include<stdio.h>
int main()
{
int i,j,count=0;
printf(" RED BALL WHITE BALL BLACKBALL\n");
printf("…………………………………………..\n");
for(i=0;i<=3;i++) /*循环控制变量i控制任取红球个数0 ̄3*/
for(j=0;j<=3;j++) /*循环控制变量j控制任取白球个数0 ̄3*/
if((8-i-j)<=6)
printf(" %2d: %d %d %d\n",++count,i,j,8-i-j);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -