根据销售总金额,以及每张发票能开的最大金额,求本次开发票的最少张数算法?

ccnccyj 2009-08-28 04:06:30
根据销售总金额,以及每张发票能开的最大金额,求本次开发票的最少张数算法?

名称 单价(元) 数量 金额
商品A 100.00 10,000 1,000,000
商品B 85.36 5,000 426,800
商品C 128.00 800,0 1,024,000
....

合计: 2,450,800

每张发票最大金额10万元,求开发票最少张数?以及每张发票包含的哪些商品及相应数量?
...全文
175 1 收藏 7
写回复
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
linren2 2009-08-29
对6楼程序的一个进一步的优化版:
#include <stdio.h>

int main(){
int i,j,k;
int a,b,c;
int e,f;
int x,y,z;
int u,v,w;
a=10000;b=5000;c=8000;
while(a!=0||b!=0||c!=0){
e=-1;
for(i=0;i<=a;i++){
u=i*10000;
if(u>10000000) break;
for(j=0;j<=b;j++){
v=u+j*8536;
if(v>10000000) break;
for(k=0;k<=c;k++){
w=v+k*12800;
if(w>10000000) break;
f=10000000-w;
if(e==-1||f<e){
e=f;
x=i;y=j;z=k;
if(e==0) goto FIND;
}
}
}
}
FIND:
printf("A(%4d), B(%4d), C(%4d): %.2f\n",x,y,z,(10000000-e)/100.0);
a-=x;
b-=y;
c-=z;
}
return 0;
}
回复
linren 2009-08-29
(上接5楼)

5楼程序的枚举的有些过于笨拙了……
下面是一个修改的版本
增加了退出枚举的判定……

【程序】
#include <stdio.h>

int main(){
int i,j,k;
int a,b,c;
int e,f;
int x,y,z;
a=10000;b=5000;c=8000;
while(a!=0||b!=0||c!=0){
e=-1;
for(i=0;i<=a;i++){
if(i*10000>10000000) break;
for(j=0;j<=b;j++){
if(i*10000+j*8536>10000000) break;
for(k=0;k<=c;k++){
if(i*10000+j*8536+k*12800>10000000) break;
f=10000000-(i*10000+j*8536+k*12800);
if(e==-1||f<e){
e=f;
x=i;y=j;z=k;
if(e==0) goto FIND;
}
}
}
}
FIND:
printf("A(%4d), B(%4d), C(%4d): %.2f\n",x,y,z,(10000000-e)/100.0);
a-=x;
b-=y;
c-=z;
}
return 0;
}

回复
linren 2009-08-29
(上接4楼)

【思路】
从总金额上来看2,450,800(元)/100,000(元/张)=24.508(张)
说明最优解至少需要>=25张钞票

4楼知道已经有26张的结果
“25张”就成为了最优解的一个判定方法

或许用贪心法得到的结果就是最优解……

于是写了如下的程序:

【程序】
#include <stdio.h>

int main(){
int i,j,k;
int a,b,c;
int e,f;
int x,y,z;
a=10000;b=5000;c=8000;
while(a!=0||b!=0||c!=0){
e=-1;
for(i=0;i<=a;i++){
if(i*10000>10000000) break;
for(j=0;j<=b;j++){
if(i*10000+j*8536>10000000) break;
for(k=0;k<=c;k++){
if(i*10000+j*8536+k*12800>10000000) break;
f=10000000-(i*10000+j*8536+k*12800);
if(e==-1||f<e){
e=f;
x=i;y=j;z=k;
}
}
}
}
printf("A(%4d), B(%4d), C(%4d): %.2f\n",x,y,z,(10000000-e)/100.0);
a-=x;
b-=y;
c-=z;
}
return 0;
}


上面用贪心+枚举的方法得到了4楼的结果
正好是25张(最优解)……

【PS】
这道题第一眼看上去感觉上很像是线性规划中的下料问题……
然而仔细一想
发现如果按照这个思路走下去很难实现……

后来想到了最优的判定条件(25张)
用贪心法+枚举法得到了一个最优解……

现在想想
构造最优解可以利用求公式:
10000*x+8536*y+12800*z=10000000(x>=0,y>=0,z>=0)
x、y、z整数解的办法……
回复
linren 2009-08-29
最少需要25张钞票……
A(   1), B( 650), C( 347): 100000.00
A( 1), B( 650), C( 347): 100000.00
A( 1), B( 650), C( 347): 100000.00
A( 1), B( 650), C( 347): 100000.00
A( 1), B( 650), C( 347): 100000.00
A( 1), B( 650), C( 347): 100000.00
A( 1), B( 650), C( 347): 100000.00
A( 2), B( 100), C( 713): 100000.00
A( 2), B( 100), C( 713): 100000.00
A( 2), B( 100), C( 713): 100000.00
A( 2), B( 100), C( 713): 100000.00
A( 5), B( 50), C( 744): 100000.00
A( 8), B( 0), C( 775): 100000.00
A( 8), B( 0), C( 775): 100000.00
A( 456), B( 0), C( 425): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A(1000), B( 0), C( 0): 100000.00
A( 508), B( 0), C( 0): 50800.00
Press any key to continue


如果是每种单开的话……
A需要10张钞票:
10(张)*1000(个/张)=10,000(个)

B需要5张钞票:
4(张)*1171(个/张)=4684(个)
1(张)*316(个/张)=316(个)
4684+316=5,000(个)

C需要11张钞票:
10(张)*781(个/张)=7810(个)
1(张)*190(个/张)=190(个)
7810+190=8,000(个)

只节省了1张钞票而已……
回复
whg01 2009-08-28
找一下整数规划的资料吧。
回复
whg01 2009-08-28
关键是总额要能对上。所以不能用贪心算法。
回复
huangy365 2009-08-28
1,优先让发票尽量填满
2,次之优先填单价高的商品
回复
发动态
发帖子
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
社区公告
暂无公告