小明假期同爸爸一起去书店,他选中了六本书,每本书的单价分别为:3.1 1.72 2 5.3 0.9和7.2。不巧的是,爸爸兜里只带了十几块钱,为了让小明过一个愉快的假期,爸爸仍然同意买书,但提出了一个要求,要小明从六本中选出若干本,使得单价相加所得的和同10最接近。你能够帮助小明解决这个问题吗?
1.问题分析与算法设计
分析题意,可将题目简化为:从六个书中选出若干个求和,使得与10的差值最小。
题目中隐含两个问题。其一是怎样从六个书中选出若干个数;其二是求与10的差。
从六个数中选出若干个数实质是从六个数中选出若干个进行组合。每个数在组合过程中只有两种情况:要么是选中参加求和,要么是没选中不参加求和。这样就可以使用六重循环对每个数是否参加求和进行全部可能的情况组合。
关于求与10的差值应当注意的是:差值的含义是指差的绝对值。例如:“9-10=-1”和“11-10=1”,但9和11这两者与10的差值都是“1”。若认为“9”与“10”的差值为“-1”就错了。
2.程序与程序注释
#include <stdio.h>
#include <math.h>
void main()
{
int d[6],m,i,j;
long b[63],flag;
float c[6],min,x;
printf("Pleace enter the prices of 6 books:");
for(i=0;i<6;i++)
{
scanf("%f",&c[i]);//输入六个浮点数
}
for(i=0,min=-1,d[0]=0;d[0]<2;d[0]++) //建立六个数的全部组合并处理
{ //i:差值具有min组合的数量
//min:与10的最小差值
for(d[1]=0;d[1]<2;d[1]++)
{
for(d[2]=0;d[2]<2;d[2]++)
{
for(d[3]=0;d[3]<2;d[3]++)
{
for(d[4]=0;d[4]<2;d[4]++)
{
for(d[5]=0;d[5]<2;d[5]++)
{
//flag:将六个数的组合用对应的一个十进制位表示
for(flag = 0,x=0,j=5;j>=0;j--) //对应六个数组合的和
{
x += c[j]*d[j];
flag = flag * 10 +d[j];
}
x = ((x-10>0)?x-10:10-x); //x:组合的和与10的差
if(min<0)
{
min = x; //对第一次计算出的差min进行处理
b[i++] = flag; //b[]:记录有相同min的flag的数组
}
else if(min-x>1.e-6)//对新的min的处理
{
min = x;
b[0] = flag;
i=1;
}
else if(fabs((double)x-min)<1.e-6)
{
b[i++] = flag; //对相等min的处理
}
}
}
}
}
}
}
for(m=0;m<i;m++) //输出全部i个与10的差值均为min的组合
{
printf(" 10(+ -)%.2f=",min);
for(flag=b[m],j=0;flag>0;j++,flag/=10)
{
if(flag%10) //将b[]中存的标记flag还原为各个数的组合
{
if(flag>1)
{
printf("%.2f+",c[j]);
}
else
{
printf("%.2f\n",c[j]);
}
}
}
}
}
3.运行结果
输入 3.1 1.7 2.0 5.3 0.9 7.2
10(+-) 0.10 = 2.00+0.90+7.20
10(+-) 0.10 = 1.70+2.00+5.30+0.90
10(+-) 0.10 = 3.10+1.70+5.30