博文
70.魔术师的猜牌术(2)(2005-09-10 15:18:00)
摘要:70.魔术师的猜牌术(2)
魔术师再次表演,他将红桃和黑桃全部迭在一起,牌面朝下放在手中,对观众说:最上面一张是黑桃A,翻开后放在桌上。以后,从上至下每数两张全依次放在最底下,第三张给观众看,便是黑桃2,放在桌上后再数两张依次放在最底下,第三张给观众看,是黑桃3。如此下去,观众看到放在桌子上牌的顺序是:
黑桃 A 2 3 4 5 6 7 8 9 10 J Q K
红桃 A 2 3 4 5 6 7 8 9 10 J Q K
问魔术师手中牌的原始顺序是什么?
*问题分析与算法设计
本题可在上题的基础上进行编程,不同的在于计数的方法和牌的张数,这些并不影响我们求解题目的思路,仍可按照倒推的方法,得到原来魔术师手中的牌的顺序。
*程序与程序注释
#include<stdio.h>
int a[27];
void main()
{
int i,n,j=1;
a[1]=1; /*初始化第一张牌*/
printf("The original order of cards is:(r:rad b:block):\n");
for(i=2;i<=26;i++)
{
n=1;
do{
if(j>26) j=1; /*超过最后一个元素则指向1号元素*/
if(a[j]) j++; /*跳过非空的盒子,不进行计数*/
else{
if(n==3) a[j]=i; /*若数到第3个空盒子,则将牌放入空盒中*/
j++; n++; /*对空盒计数,数组下标指向下一个盒子*/
}
}while(n<=3); /*控制空盒计数为3*/
}
for(i=1;i<=26;i++) /*输出牌的排列顺序*/
{
printf("%c",a[i]>13? 'r':'b');
printf("%d ",a[i]>13? a[i]-13:a[i]);
if(i==13) printf("\n");
}
printf(&qu......
69.魔术师的猜牌术(1)(2005-09-10 15:18:00)
摘要:69.魔术师的猜牌术(1)
魔术师利用一副牌中的13张黑桃,预先将它们排好后迭在一起,牌面朝下。对观众说:我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听,不信?你们就看。魔术师将最上面的那张牌数为1,把它翻过来正好是黑桃A,将黑桃A放在桌子上,然后按顺序从上到下数手上的余牌,第二次数1、2,将第一张牌放在这迭牌的下面,将第二张牌翻过来,正好是黑桃2,也将它放在桌子上,第三次数1、2、3,将前面两张依次放在这迭牌的下面,再翻第三张牌正好是黑桃3。这样依次进行将13张牌全翻出来,准确无误。问魔术师手中的牌原始顺序是怎样安排的?
*问题分析与算法设计
题目已经将魔术师出牌的过程描述清楚,我们可以利用倒推的方法,很容易地推出原来牌的顺序。
人工倒推的方法是:在桌子上放13空盒子排成一圈,从1开始顺序编号,将黑桃A放入1号盒子中,从下一个空盒子开始对空的盒子计数,当数到第二个空盒子时,将黑桃2放入空盒子中,然后再从下一个空盒子开始对空盒子计数,顺序放入3、4、5...,直到放入全部3张牌。注意在计数时要跳过非空的盒子,只对空盒子计数。最后牌在盒子中的顺序,就是魔术师手中原来牌的顺序。
这种人工的方法是行之有效的,计算机可以模拟求解。
*程序与程序注释
#include<stdio.h>
int a[14];
void main()
{
int i,n,j=1; /*j:数组(盒子)下标,初始时为1号元素*/
printf("The original order of cards is:");
for(i=1;i<=13;i++) /*i:要放入盒子中的牌的序号*/
{
n=1;
do{
if(j>13) j=1; /*由于盒子构成一个圈,j超过最后一个元素则指向1号元素*/
if(a[j]) j++; /*跳过非空的盒子,不进行计数*/
else{ if(n==i) a[j]=i; /*若数到第i个空盒子,则将牌放入空盒中*/
j++;n++; /*对空盒计数,数组下标指向下一个盒子*/
}
}while(n<=i); /*控制空盒计数为i......
68.九位累进可除数(2005-09-10 15:18:00)
摘要:68.九位累进可除数
求九位累进可除数。所谓九位累进可除数就是这样一个数:这个数用到1到9这九个数字组成,每个数字刚好只出现一次。这九个位数的前两位能被2整除,前三位能被3整除......前N位能被N整除,整个九位数能被9整除。
*问题分析与算法设计
问题本身可以简化为一个穷举问题:只要穷举每位数字的各种可能取值,按照题目的要求对穷举的结果进行判断就一定可以得到正确的结果。
问题中给出了“累进可除”这一条件,就使得我们可以在穷举法中加入条件判断。在穷举的过程中,当确定部分位的值后,马上就判断产生的该部分是否符合“累进可除”条件,若符合,则继续穷举下一位数字;否则刚刚产生的那一位数字就是错误的。这样将条件判断引入到穷举法之中,可以尽可能早的发现矛盾,尽早地放弃不必要穷举的值,从而提高程序的执行效率。
为了达到早期发现矛盾的目的,不能采用多重循环的方法实行穷举,那样编出的程序质量较差。程序中使用的算法不再是穷举法,而是回朔法。
*程序与程序注释
#include<stdio.h>
#define NUM 9
int a[NUM+1];
void main()
{
int i,k,flag,not_finish=1;
long sum;
i=1;
/*i:正在处理的数组元素,表示前i-1个元素已经满足要求,正处理的是第i个元素*/
a[1]=1; /*为元素a[1]设置初值*/
while(not_finish) /*not_finish=1:处理没有结束*/
{
while(not_finish&&i<=NUM)
{
for(flag=1,k=1;flag&&k<i;k++)
if(a[k]==a[i])flag=0; /*判断第i个元素是否与前i-1个元素重复*/
for(sum=0,k=1;flag&&k<=i;k++)
{
sum=10*sum+a[k];
if(sum%k)flag=0; /*判断前k位组成的整数是否能被k整除*/
}
if(!flag) /*fla......
67.除式还原(2)(2005-09-10 15:20:00)
摘要:67.除式还原(2)
下列除式中仅在商中给定了一个7,其它打×的位置全部是任意数字,请还原。
×7××× -------------商
------------------
除数 -------------------×××| ×××××××× -------------被除数
×××× -------------1)
---------------
××× -------------2)
××× -------------3)
---------------
×××× -------------4)
××× -------------5)
-----------------
×××× -------------6)
×××× -------------7)
-----------------
0
*题目分析与算法设计
这道题是不可能用单纯的穷举法求解的,一则计算时间太长,二则难于求出除式中各部分的值。
对除式进行分析,改可能多地推出限制条件:
由3)可以看出,商的第二位7乘除数得一个三位数,所以除数<=142。
由除数乘商的第一位为一个四位数可知,商的第一位只能为8或9且除数>=112。同时商的第五位也为8或9数的前四位一定<=142*9+99且>=1000+10。
由4)、5)、6)可以看出,4)的前两位一定为“10”;5)的第一位一定为“9”;6)的前两位一定在10到99之间;商的第四位一定为为0。
由 5)的第一位一定是“9”和“112”<=除数<=142可知:商的第三位可能为7或8。
由除式本身可知:商的第四位为0。
由 1)可知:除数X商的第一位应当为一个四位数。
由 5)可知:除数X商的第三位应当为一个三位数。
编程时为了方便,将被除数分解:前四位用a[0]表示,第五位用a[1],第六位用a[2],第七八两位用a[3];除数用变量b表示;分解商:第一位用c[0],第五位用c[2];其它的部分商分别表示为:2)的前两位为d[0],4)的前三位为d[1],6)的前二位为d[2]。将上述分析用数学......
66.除式还原(1)(2005-09-10 15:18:00)
摘要:66.除式还原(1)
给定下列除式,其中包含5个7,其它打×的是任意数字,请加以还原。
× 7 × --------------商
--------------
除数------××| ×××××-------------被除数
×7 7
--------------
× 7 ×
× 7 ×
----------
× ×
× ×
----------
○
*题目分析与算法设计
首先分析题目,由除式本身尽可能多地推出已知条件。由除式本身书已知:
1、被除数的范围是10000到99999,除数的范围是10到99,且可以整除;
2、商为100到999之间,且十位数字为7;
3、商的第一位与除数的积为三位数,且后两位为77;
4、被除数的第三位一定为4;
5、 7乘以除数的积为一个三位数,且第二位为7;
6、商的最后一位不能为0,且与除数的积为一个二位数。
由已知条件就可以采用穷举的方法找出结果。
*程序与程序注释
#include<stdio.h>
void main()
{
long int i;
int j,l;
for(i=10000;i<=99999;i++) /*1. i:被除数*/
if(i%1000-i%100==400) /*4. 被除数的第三位一定为4*/
for(j=10;j<=99;j++) /*1. j: 余数*/
if(i%j==0&&(l=i/j)%100>=70&&l%100<80&&l%10!=0&&l>100&&l<=999)
/*1. 可以整除&& 2.商l在100到999之间且十位数字为7&&6.商的个数不能为0*/
if((j*(l%10))<100&&j*(l%10)>10) /*6. 商的个数与除数的积为二位数*/
if(j*7%100>=70&......
65.乘式还原(2)(2005-09-10 15:18:00)
摘要:65.乘式还原(2)
有乘法算式如下:
○○○
× ○○
------------
○○○○
○○○○
------------
○○○○○
18个○的位置上全部是素数(1、3、5或7),请还原此算式。
*问题分析与算法设计
问题中虽然有18数位,但只要确定乘数和被乘数后经过计算就可确定其它的数位。
乘数和被乘数共有5个数位,要求每个数都是质数。完全可以采用穷举的方法对乘数和被乘数进行穷举,经过判断后找出答案。但是这种方法给人的感觉是“太笨了”,因为组成的数字只是质数(4个),完全没有必要在那么大的范围内进行穷举,只需要试探每一位数字为质数时的情况即可。
采用五重循环的方法实现对于5个数字的穷举,前面的许多例题中都已见过。循环实现简单易行,但嵌套的层次太多,需要穷举的变量的数量直接影响到循环嵌套的层数,这种简单的实现方法缺少技巧性。本例的程序中给出了另外一种同样功能的算法,该算法的实现思想请阅读程序。
程序中并没有直接对质数进行穷举,而是将每个质数与1到4顺序一一对应,在穷举时为处理简单仅对1到4进行穷举处理,待要判断产生的乘积是否满足条件时再利用一个数组完成向对应质数的转换。请体会程序中的处理方法。程序中使用的算法实际上是回朔法。
*程序与程序注释
#include<stdio.h>
#define NUM 5 /*需要穷举的变量数目*/
#define C_NUM 4 /*每个变量的值的变化范围*/
int a[NUM+1]; /*为需要穷举的变量开辟的数组*/
/*a[1]:被乘数的百位,a[2]:十位,aa[3]:个位 a[4]:被乘数的十位 a[5]:个位*/
int b[]={0,2,3,5,7}; /*存放质数数字的数组,不使用第0号元素*/
int f(long sum);
void main()
{
int i,not_finish=1;
i=2; /*i:将要进行处理的元素的指针下标。设置初始值*/
a[1]=1; /*为第1号元素设置初始值*/
while(not_finish) /*not_fini......
64.乘式还原(2005-09-10 15:20:00)
摘要:64.乘式还原
A代表数字0到9中的前五个数字,Z代表后五个数字,请还原下列乘式。
A Z A
× A A Z
------------
A A A A
A A Z Z
Z A A
------------
Z A Z A A
*问题分析与算法设计
问题本身并不复杂,可以对乘式中的每一位使用穷举法,最终可以得到结果。本题的关键在于怎样有效的判断每个部分积的每一位是否满足题意,这一问题处理不好,编写的程序会很长。程序实现中采用了一个判断函数,通过传入函数的标志字符串对所有的数进行统一的判断处理。
*程序与程序注释
#include<stdio.h>
void print(long a,long b,long s1,long s2,long s3);
int jud(long q,char *pflag);
void main()
{
long i,j,k,l,m,n,term,t1,t2,t3;
int flag;
for(i=0;i<=4;++i) /*被乘数的第一位*/
for(j=5;j<=9;++j) /*被乘数的第二位*/
for(k=0;k<=4;++k) /*被乘数的第三位*/
{
term=100*i+10*j+k; /*被乘数*/
for(flag=0,n=0;n<4&&!flag;) /*乘数的第一位*/
flag=jud((t3=++n*100*term)/100,"001"); /*判断第三个部分积*/
if(flag)
{
for(flag=0,m=0;m<4&&!flag;) /*乘数的第二位*/
flag=jud((t2=++m*10*term)/10,"1100"); /*判断第二个部分积*/
if(flag)
{
for(flag=0,l=5;l<9&&!flag;) /*乘数的第三位*/
flag=jud(t1=++l*term,&......
63.减式还原(2005-09-10 15:20:00)
摘要:63.减式还原
编写程序求解下式中各字母所代表的数字,不同的字母代表不同的数字。
PEAR
- ARA
--------
PEA
*问题分析与算法设计
类似的问题从计算机算法的角度来说是比较简单的,可以采用最常见的穷举方法解决。程序中采用循环穷举每个字母所可能代表的数字,然后将字母代表的数字转换为相应的整数,代入算式后验证算式是否成立即可解决问题。
*程序与程序注释
#include<stdio.h>
void main()
{
int p,e,a,r;
for(p=1;p<=9;p++) /*从1到9穷举字母p的全部可能取值*/
for(e=0;e<=9;e++) /*从0到穷举字母e的全部可能取值*/
if(p!=e) /*p不等于e*/
for(a=1;a<=9;a++) /*从0到9穷举字母a的全部可能取值*/
if(a!=p&&a!=e)
for(r=0;r<=9;r++) /*从0到9穷举字母r的全部可能取值*/
if(r!=p&&r!=e&&r!=a&&p*1000+e*100+a*10+r-(a*100+r*10+a)
==p*100+e*10+a)
{
printf(" PEAR %d%d%d%d\n",p,e,a,r);
printf(" -ARA - %d%d%d\n",a,r,a);
printf(".........................\n");
printf(" PEA %d%d%d\n",p,e,a);
}
}
*运行结果
PEAR 1098
- ARA - 989
---------- ------
PEA 109
*思考题
请复原下面的和式。不同的字母代表不同的数字。
SEVEN 82524 82526
THREE 19722 19722
......
62.由8个整数形成奇特的立方体(2005-09-10 15:20:00)
摘要:62.由8个整数形成奇特的立方体
任意给出8个整数,将这8个整数分别放在一个立方体的八个顶点上,要求每个面上的四个数之和相等。
*问题分析与算法设计
简化问题:将8个顶点对应数组中的8个元素,将“每个面上的四个数之和皆相等”转换为数组无素之间和的相等关系。这里的关键在于正确地将立方体的8个顶点与数组的8个元素对应。
可以利用简单的穷举方法建立8个数的全部排列。
*程序与程序注释
#include<stdio.h>
#include<stdlib.h>
void main()
{
int a[9],ii=0,i,a1,a2,a3,a4,b1,b2,b3,b4,flag;
for(i=1;i<=8;i++) /*输入个数*/
{
printf("Please enter [%d]number:",i);
scanf("%d",&a[i]);
ii+=a[i];
}
printf("******************************************\n");
if(ii%2) /*和为奇数则输入的8个数不可用*/
{
printf("Sorry they can't be constructed required cube!\n");
exit(0);
}
for(flag=0,a1=1;a1<=8;a1++) /*flag:完成标记.flag=1;表示完成*/
for(a2=1;a2<=8;a2++) /*采用八重循环建立八个整数的全排列*/
if(a2!=a1) /*前两个数不能相同*/
for(a3=1;a3<=8;a3++)
if(a3!=a2&&a3!=a1) /*前三个数不能相同*/
for(a4=1;a4<=8;a4++)
if(a4!=a3&&a4!=a2&&a4!=a1) /*前四个数不能相同*/
for(b1=......
61.1~9组成三个3位的平方数(2005-09-10 15:19:00)
摘要:61.1~9组成三个3位的平方数
将1、2、3、4、5、6、7、8、9九个数字分成三组,每个数字只能用一次,即每组三个数不允许有重复数字,也不许同其它组的三个数字重复,要求每组中的三位数都组成一个平方数。
*问题分析与算法设计
本问题的思路很多,这里介绍一种简单快速的算法。
首先求出三位数中不包含0且是某个整数平方的三位数,这样的三位数是不多的。然后将满足条件的三位数进行组合,使得所选出的3个三位数的9个数字没有重复。
程序中可以将寻找足条件的三位数的过程和对该三位数进行数字分解的过程结合起来。
*程序与程序注释
#include<stdio.h>
void main()
{
int a[20],num[20][3],b[10]; /*a:存放满足条件的三位数*/
/*若不是10 的倍数,则分解三位数*/
/*分解该三位数中的每一个数字*/
int i,j,k,m,n,t,flag;
printf("The 3 squares with 3 different digits each are:\n");
for(j=0,i=11;i<=31;i++) /*求出是平方数的三位数*/
if(i%10!=0) /*若不是10的倍数,则分解三位数*/
{
k=i*i; /*分解该三位数中的每一个数字*/
num[j+1][0]=k/100; /*百位*/
num[j+1][1]=k/10%10; /*十位*/
num[j+1][2]=k%10; /*个位*/
if(!(num[j+1][0]==num[j+1][1]||num[j+1][0]==num[j+1][2]||
num[j+1][1]==num[j+1][2])) /*若分解的三位数字均不相等*/
a[++j]=k; /*j:计数器,统计已找到的满足要求的三位数*/
}
for(i=1;i<=j-2;++i) /*从满足条件的三位数中选出三个进行组合*/
{
b[1]=num[i][0];
b[2]=num[i][1];
b[3]=......