例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;
}