百钱买百鸡算法的扩展,动态for循环构造收藏
CSDN上 有人出了一个题,有三种物品的价格如下:1.2,3.4,6.2。现在已知一个总价14.2,要求三种物品各取多少个时其求和的总价与给定的总价相等。这其实就是典型的百钱买百鸡问题。只不过不一样的是,要求构造的程序不限制物品及其价格的数量,即可能是3种,4种或者几十上百种物品及其价格。
对于典型的百钱百鸡问题,由于知道是三种价格,所以用三个for循环来穷举所有可能,再求和看与给定的总价是否相等来找到所有的解。但在本题中,由于物品种数是变化的,所以不能采用固定的for循环来完成,但又需要同样采用穷举的思路,所以必须对算法有所改进。
设有n个物品a1, a2, ..., an,对应n个价格p1, p2, ..., pn,而要求的总价格是P,即a1*p1+a2*p2+...+an*pn=P。我们依然可以利用百钱百鸡问题的思路来穷举,即:
设i=1, 2, ..., n
令a(i)=0, 1, 2, ..., P/p(i)
对a(i)*p(i)求和,如果结果等于P,则找到一个答案。
不过,由于不能确定循环总数,我们只能推算每个a(i)的值。思路是现令a(i)等于0,再令a(n)=1, 2, ..., P/p(n)。从a(n)反推前面的a(i),即由a(i)==>a(i-1),当a(i)大于P/p(i)时,令a(i)=0,a(i-1)=a(i+1),直到a(0)>P/p(0)。
当然,为了提高效率,减少循环次数,我们还可以修改a(i)>P/p(i)的条件,以剔出显然不可能的组合,即先计算a(0)*p(0)+a(1)*p(1)+...+a(i-1)*p(i-1)=Pt,若a(i)>(P-Pt)/p(i)时,则可以停止a(i)的递增,进行a(i)初始化和a(i-1)的递推了。这样,算法如下:
1)令a(i)=0,其中,i=0, 1, 2, ..., n
2) 当a(0)<P/p(0),进行下列步骤,否则,退出
3)求total=a(0)*p(0)+a(1)*p(1)+...+a(n)*p(n)
4)若total=P,则输出结果
5)a(n)=a(n)+1
6)令j=n, n-1, ..., 0,执行到步骤8)
7)求Pt=a(0)*p(0)+a(1)*p(1)+...+a(j-1)*p(j-1)
8)若a(j)>(P-Pt)/p(j),则a(j)=0,a(j-1)=a(j-1)+1
9)返回步骤2)
下面是相应算法的Java程序:
public class test {
public static void main(String[] arg) {
double p[]={1.2,6.2,3.4,2.3};
int a[]=new int[p.length],loop=0;
double price=16.5;
for(int i=0; i<p.length; i++) a[i]=0;
while(a[0]<price/p[0]) {
double total=0;
loop++;
for(int i=0; i<a.length; i++) total+=a[i]*p[i];
if(total==price) {
for(int i=0; i<a.length-1; i++)
System.out.print(a[i]+"*"+p[i]+"+");
System.out.println(a[a.length-1]+"*"+p[p.length-1]+"="+price);
}
a[a.length-1]++;
for(int i=a.length-1; i>0; i--) {
total=0;
for(int j=0; j<i-1; j++) total+=a[j]*p[j];
if(a[i]>(price-total)/p[i]) {
a[i]=0;
a[i-1]++;
}
}
}
System.out.println("Total Num:"+loop);
}
}
下面是运行结果:
0*1.2+1*6.2+1*3.4+3*2.3=16.5
1*1.2+1*6.2+2*3.4+1*2.3=16.5
8*1.2+0*6.2+0*3.4+3*2.3=16.5
9*1.2+0*6.2+1*3.4+1*2.3=16.5
Total Num:400
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/JianZhiZG/archive/2007/03/08/1524334.aspx