C语言程序设计100例之(33):加法算式
例33 加法算式
问题描述
看这个加法算式:
☆☆☆ + ☆☆☆ = ☆☆☆
如果每个五角星代表 1 ~ 9 的不同的数字。
这个算式有多少种可能的正确填写方法?
173 + 286 = 459
295 + 173 = 468
173 + 295 = 468
183 + 492 = 675
以上都是正确的填写法!
注意:111 + 222 = 333 是错误的填写法!因为每个数字必须是不同的! 也就是说:1~9中的所有数字,每个必须出现且仅出现一次!不包括数字“0”!
另外,满足加法交换率的式子算两种不同的答案。
输入格式
无输入。
输出格式
一个整数,表示可能的算式总数。
(1)编程思路。
对1-9进行全排列,然后检查每种排列是否满足加法等式要求。
(2)源程序。
#include <stdio.h>
int cnt=0;
void dfs(int a[10],int pos)
{
if(pos>9)
{
int num1=a[1]*100+a[2]*10+a[3];
int num2=a[4]*100+a[5]*10+a[6];
int num3=a[7]*100+a[8]*10+a[9];
if (num1+num2==num3)
{
// printf("%d + %d = %d\n",num1,num2,num3);
cnt++;
}
}
else
for(int i=pos;i<=9;i++)
{
int temp = a[i];
a[i] = a[pos];
a[pos] = temp;
dfs(a,pos+1); // 递归
temp = a[i];
a[i] = a[pos];
a[pos] = temp;
}
}
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
dfs(a,1);
printf("%d\n",cnt);
return 0;
}
习题33
33-1 排座位
问题描述
有3个A国人、3个B国人和3个C国人坐成一排照相。要求任意两个同一国籍的人不能坐在一起。例如,“A1、B1、A3、B2、C1、B3、C2、A2、C3”就是一种可行的坐法,而“A1、B1、A3、B2、C1、B3、C2、C3、A2”就不满足要求,因为此时坐在第7和第8两个位置的人都是C国人。
求所有位置安排的不同方案总数?
输入格式
无输入。
输出格式
一个整数,表示可行的位置安排总数。
(1)编程思路。
不妨将9个人分别编号为11、12、13、21、22、23、31、32、33,这样编号后,编号十位数相同的人一定是同一个国籍。对{11,12,13,21,22,23,31,32,33}这9个数进行全排列,然后判断每种排列是否符合要求。
(2)源程序。
#include <stdio.h>
int cnt=0;
int judge(int a[10]) // 判断同一个国家的两个人是否挨着
{
for (int i=1;i<=8;i++)
{
if(a[i]/10==a[i+1]/10) return 0;
}
return 1;
}
void dfs(int a[10],int pos)
{
if(pos>9)
{
if (judge(a)==1)
{
cnt++;
}
}
else
for(int i=pos;i<=9;i++)
{
int temp = a[i];
a[i] = a[pos];
a[pos] = temp;
dfs(a,pos+1); // 递归
temp = a[i];
a[i] = a[pos];
a[pos] = temp;
}
}
int main()
{
int a[10]={0,11,12,13,21,22,23,31,32,33};
dfs(a,1);
printf("%d\n",cnt);
return 0;
}
33-2 猜算式
问题描述
看下面的算式:□□ x □□ = □□ x □□□ 它表示:两个两位数相乘等于一个两位数乘以一个三位数。如果没有限定条件,这样的例子很多。
给出限定是:这9个方块,表示1~9的9个数字,不包含0。该算式中1至9的每个数字出现且只出现一次!
比如:
46 x 79 = 23 x 158
54 x 69 = 27 x 138
54 x 93 = 27 x 186
…
请编程,输出所有可能的情况! 注意:左边的两个乘数交换算同一方案,不要重复输出!
输入格式
无输入。
输出格式
输出所有满足要求的乘法等式,每个等式占1行。
输入样例
无输入
输出样例
46*79=23*158
54*69=27*138
54*93=27*186
…… (省略的其他解的情况)
(1)编程思路1。
对1-9进行全排列,然后检查每种一次填入9个方框后是否满足乘法等式要求。为了不重复输出,输出时保证左边的两个乘数小数在前,大数在后。
(2)源程序1。
#include <stdio.h>
void dfs(int a[10],int pos)
{
if(pos>9)
{
int n1=a[1]*10+a[2];
int n2=a[3]*10+a[4];
int n3=a[5]*10+a[6];
int n4=a[7]*100+a[8]*10+a[9];
if (n1<n2 && n1*n2==n3*n4)
{
printf("%d*%d=%d*%d\n",n1,n2,n3,n4);
}
}
else
for(int i=pos;i<=9;i++)
{
int temp = a[i];
a[i] = a[pos];
a[pos] = temp;
dfs(a,pos+1); // 递归
temp = a[i];
a[i] = a[pos];
a[pos] = temp;
}
}
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
dfs(a,1);
return 0;
}
(3)编程思路2。
设乘法算式中从左到右的四个数分别为a、b、c、d,用三重循环对a、b、c这三个两位数进行穷举。其中10≤a≤97,a+1≤b≤98, 10≤c≤98。对穷举的每种情况,若a和b的积能整除c,则计算出d,然后判断这4个数中1~9这9个数字是否全部出现。
为判断数字1~9是否都出现。定义数组int hash[10],其元素初始值全为0,hash[i]=0表示数字i未出现,数字i出现过,置hash[i]=1。
(4)源程序2。
#include <stdio.h>
int main()
{
int a,b,c,d,i;
int hash[10];
for (a=10; a<=97; a++)
for (b=a+1; b<=98; b++)
for (c=10; c<=98; c++)
{
if ((a*b)%c==0)
{
d=a*b/c;
for (i=0;i<10;i++)
hash[i]=0;
hash[a/10]=1; hash[a%10]=1;
hash[b/10]=1; hash[b%10]=1;
hash[c/10]=1; hash[c%10]=1;
hash[d/100]=1; hash[d/10%10]=1; hash[d%10]=1;
for (i=1;i<=9;i++)
if (hash[i]==0) break;
if (i>9)
printf("%d*%d=%d*%d\n",a,b,c,d);
}
}
return 0;
}
33-3 三个3位平方数
问题描述
将1、2、3、4、5、6、7、8、9九个数字分成三组,每组三个数字构成一个三位数,要求每组中的三位数都组成一个平方数。
试求出满足要求的3个三位数。
输入格式
无输入。
输出格式
三个从小到大排列的3位整数。
(1)编程思路1。
仿照例33的做法,生成1~9的全排列,再判断全排列的每种情况构成的3个三位数是否都是平方数。
(2)源程序1。
#include <stdio.h>
#include <math.h>
void dfs(int a[10],int pos)
{
if(pos>9)
{
int num1=a[1]*100+a[2]*10+a[3];
int num2=a[4]*100+a[5]*10+a[6];
int num3=a[7]*100+a[8]*10+a[9];
int i=(int)sqrt(1.0*num1);
int j=(int)sqrt(1.0*num2);
int k=(int)sqrt(1.0*num3);
if (i*i==num1 && j*j==num2 && k*k==num3)
{
printf("%d %d %d\n",num1,num2,num3);
}
}
else
for(int i=pos;i<=9;i++)
{
int temp = a[i];
a[i] = a[pos];
a[pos] = temp;
dfs(a,pos+1); // 递归
temp = a[i];
a[i] = a[pos];
a[pos] = temp;
}
}
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
dfs(a,1);
return 0;
}
源程序1运行后输出如下的结果。
361 529 784
361 784 529
529 784 361
529 361 784
784 361 529
784 529 361
这6个结果按从小到大排列后,本质是一个结果。因此,程序中还需进行去重。
(3)编程思路2。
按思路1虽然可以求出3个3位平方数,但并不是这题理想的解法。
实际上,3位平方数最多有21个(11的平方到31的平方)。因此我们可以先求出所有三位平方数,并且将这些数中出现数字0或存在重复数字的数去掉,例如121、144等。这样的三位平方数一定少于21个,设有cnt个。再在这cnt个数中任意选取3个数进行组合,看每种组合中的3个3位数的数字是否全部不相同,正好1~9每个数字出现一次。
为判断数字1~9是否都出现。定义数组int hash[10],其元素初始值全为0,hash[i]=0表示数字i未出现,数字i出现过,置hash[i]=1。
(4)源程序2。
#include <stdio.h>
int a[3];
int cnt=0;
void dfs(int p[],int pos,int num)
{
if (pos==3)
{
int hash[10],i;
for (i=0;i<10;i++)
hash[i]=0;
hash[a[0]/100]=1; hash[a[0]/10%10]=1; hash[a[0]%10]=1;
hash[a[1]/100]=1; hash[a[1]/10%10]=1; hash[a[1]%10]=1;
hash[a[2]/100]=1; hash[a[2]/10%10]=1; hash[a[2]%10]=1;
for (i=1;i<=9;i++)
if (hash[i]==0) break;
if (i>9)
printf("%d %d %d\n",a[0],a[1],a[2]);
return;
}
if(3-pos>cnt-num+1) return ;
for(int i=num;i<cnt;i++)
{
a[pos]=p[i];
dfs(p,pos+1,i+1);
}
}
int main()
{
int p[20];
int i;
for (i=11;i<=31;i++)
{
int a=(i*i)/100;
int b=(i*i)/10%10;
int c=(i*i)%10;
if (a==0 || b==0 ||c==0) continue;
if (a==b || a==c || b==c) continue;
p[cnt++]=i*i;
}
dfs(p,0,0);
return 0;
}