老婆叫我写一个算法,竟然想了一晚上没想出来,感觉还是有难度

时间:2021-08-25 08:07:32
她是搞会计的,叫我帮她写个算法,竟然想了一晚上没想出来
 
有个列表如下  

品名  价格
a     1.2  
b     3.4  
c     6.2  
.....  
 
列表数量不确定.会有更多(用合计总价凑出单个数量来)  
 
现在要求  求出  a1,a2,a3    表示数量
价格 * 数量(未知) = 已知

1.2  *  a1  +  3.4  *  a2  +  6.2  *  a3  =  14.2  (合计总价,动态得到)  
 
(a1,a2,a3  ...=An为整数,可以设置An最大数)  
 
本列得到An为2时:a1=1;a2=2;a3=1  
 
当然会有多个答案,都输出来。  
 
注意列表数,和An数据比较大的时候的速度  

59 个解决方案

#1


楼主题意没有表达清楚,An是什么意思?

(a1,a2,a3  ...=An为整数,可以设置An最大数)  
这是说a1+a2+a3..=An?还是什么意思

表达能力还需锻炼阿


#2


(a1,a2,a3  ...=An为整数,可以设置An最大数)  
这是说a1+a2+a3..=An?还是什么意思
============================================================
就是说a1,a2,a3 <= An
理解能力也需要锻炼阿

#3


for(int a1=0; a1<14.2 % 1.2 && a1 < An; a1 ++) {
    for(int a2=0; a2<14.2 % 3.4 && a2 < An; a2 ++) {
    for (int a3=0; a3 <6.2 % 3.4 && a3 < An; a3 ++) {
             if ( 1.2  *  a1  +  3.4  *  a2  +  6.2  *  a3  ==  14.2 ) {
println ("a1:" & a1 " a2:" & a2  & " a3:" & a3
}
    }
    }
}

#4


经过优化,可以是这样
for(int a1=0; a1<14.2 % 1.2 && a1 < An; a1 ++) {
    for(int a2=0; a2<14.2 % 3.4 && a2 < An; a2 ++) {
    
             if ( (14.2 - (1.2  *  a1  +  3.4  *  a2)) mod 6.2 == 0 ) {
println ("a1:" & a1 " a2:" & a2  & " a3:" & (14.2 - (1.2  *  a1  +  3.4  *  a2)) % 6.2)
}
    
    }
}

#5


学习中..............

#6


学习
学习
学习

#7


学写啊,学习啊

#8


我的想法(不用太在意):
用动态规划的方法做。

有个问题先:
单个物品的价格有没有最大值?

#9


jornet(匆匆) 的算法明显不行。。如果AN很大的时候那运算量会指数级增长。。效率太低。有几个品种就要加上几个FOR循环。

我有点思路就是。先用2分法确定AN有效的范围,比如AN非常大的时候,如LZ的例子,AN如果=10,但是a1,a2,a3不可能取到这个10这个值的,可以不用计算。这样可以优化。

至于具体的解法。。还没想出来。单纯的循环嵌循环效率太低了

#10


double sum = 14.2;
double param=0;
int a1=0,a2=0,a3=0;

for(int i=0;i<=14.2/1.2;i++){
param=sum;
a1=i;
param = 14.2-a1*1.2;
int j=0;
a2=0;
a3=0;
while(a1*1.2+a2*3.4+a3*6.2<14.2){
a2=j++;
a3=(int) ((param-a2*3.4)/6.2);
if(a1*1.2+a2*3.4+a3*6.2==14.2){
System.out.println("a1:" + a1 + " a2:" + a2  
+ " a3:" + a3);
}

}
}

#11


我在来表述一遍,上边提到的An表示物品数量列表 相当 a1,a2,a3....

品名 价格   数量
a    1.2     a1
b    3.4     a2
c    6.2     a3
.....
列表数量不确定.会有更多(用合计总价凑出单个数量来)
现在知道合计总价

公式入下,求物品的数量.
价格1 * 数量1(未知) + 价格2 * 数量2(未知) + .....= 合计总价

#12


to:jornet(匆匆) 你的方法不对 An 表示的是数量列表,并不是一个数.

#13


不单单这三个数会有更多,上百千个
a   1.2
b   3.4
c   6.2
f   3.6
y   9.1
z   1.3
h   7.4
.....

#14


感觉这是一个矩阵的问题,用那里面的数学知识解决可能比较好.不过毕业后就都忘了:(
描述:
price=(p1,p2,p3,……pn)

quantity=(q11,q12,q13……q1m
          q21,q22,q23……q2m
          q31,q32,q33……q3m
          ……
          qn1,qn2,qn3……qnm)

result=(r1,r2,r3,……rn)

r1=r2=r3=……=rn
price*quantity=result
求 quantity

不知道这样描述对不对?

#15


对啊!感觉是个矩阵的问题,相当一个未知大小的矩阵(只知道矩阵的一个边)
求矩阵中和为一个数的所有列表.

因为 只知道矩阵的一个边 用循环的时候就会很麻烦.

#16


比上大学的时候学的矩阵问题难多了,

#17


学习……

#18


看不明白...

纯顶吧!

#19


看着 这个 
价格 * 数量(未知) = 已知 
1.2 * a1 + 3.4 * a2 + 6.2 * a3 = 14.2 (合计总价,动态得到) 
的条件,怎么越看越像,在PB讨论块里面的 一个算法问题啊!? 

http://community.csdn.net/Expert/TopicView3.asp?id=5370530
PB贴的大概意思是: 求数值在 1 - n 之内的任意x个数之和为y。

变通一下,把价格和总价 * 100 变为整数 ,所以就比较特殊的 情况了,可以确定价格*数量的一个总区间, 可以参考一下,


呵呵! 我也写了一个, 在现在的47楼,现在的倒数 2楼,呵呵。。。。。

#20


背包, NPC ....

#21


嘿嘿。俺只会做加法和组合类的,这个得花时间了
等有空了再说...
同时期待高人出现。

#22


我都没有明白 还是看看高手咋回答的吧

#23


背包问题

#24


大致的思路:
定义类
class Goods {
  品名
  价格
  数量; // 根据总价计算出最大数量值,并联Min(最大数量值, An), 或标记为Qn
}
把Goods放到队列遍历,记品种的数量为m种
比较次数
Q1*Q2*....Qm

如果在品种不多或者总价数值不大的情况下,运算速度还是可以保障的.

#25


做假账用的吧。
好吧,道歉,我承认这话有点不厚道。。。

#26


百度搜索到的关于背包问题的4种算法,大家共同参考学习。只是用的语言似乎是matlab什么的。。我看起来比较吃力。。下面列出4种算法

1)登上算法
用登山算法求解背包问题 function []=DengShan(n,G,P,W) %n是背包的个数,G是背包的总容量,P是价值向量,W是物体的重量向量 %n=3;G=20;P=[25,24,15];W2=[18,15,10];%输入量 W2=W; [Y,I]=sort(-P./W2);W1=[];X=[];X1=[]; for i=1:length(I) W1(i)=W2(I(i)); end W=W1; for i=1:n X(i)=0; RES=G;%背包的剩余容量 j=1; while W(j)<=RES X(j)=1; RES=RES-W(j); j=j+1; end X(j)=RES/W(j); end for i=1:length(I) X1(I(i))=X(i); end X=X1; disp('装包的方法是');disp(X);disp(X.*W2);disp('总的价值是:');disp(P*X');

时间复杂度是非指数的

#27


2)递归法
先看完全背包问题
一个旅行者有一个最多能用m公斤的背包,现在有n种物品,每件的重量分别是W1,W2,...,Wn,
每件的价值分别为C1,C2,...,Cn.若的每种物品的件数足够多.
求旅行者能获得的最大总价值。
本问题的数学模型如下:
设 f(x)表示重量不超过x公斤的最大价值,
则 f(x)=max{f(x-i)+c[i]} 当x>=w[i] 1<=i<=n
可使用递归法解决问题程序如下:
program knapsack04;
const maxm=200;maxn=30;
type ar=array[0..maxn] of integer;
var m,n,j,i,t:integer;
c,w:ar;
function f(x:integer):integer;
var i,t,m:integer;
begin
if x=0 then f:=0 else
begin
t:=-1;
for i:=1 to n do
begin
if x>=w[i] then m:=f(x-i)+c[i];
if m>t then t:=m;
end;
f:=t;
end;
end;
begin
readln(m,n);
for i:= 1 to n do
readln(w[i],c[i]);
writeln(f(m));
end.
说明:当m不大时,编程很简单,但当m较大时,容易超时.
4.2 改进的递归法
改进的的递归法的思想还是以空间换时间,这只要将递归函数计算过程中的各个子函数的值保存起来,开辟一个
一维数组即可
程序如下:
program knapsack04;
const maxm=2000;maxn=30;
type ar=array[0..maxn] of integer;
var m,n,j,i,t:integer;
c,w:ar;
p:array[0..maxm] of integer;
function f(x:integer):integer;
var i,t,m:integer;
begin
if p[x]<>-1 then f:=p[x]
else
begin
if x=0 then p[x]:=0 else
begin
t:=-1;
for i:=1 to n do
begin
if x>=w[i] then m:=f(i-w[i])+c[i];
if m>t then t:=m;
end;
p[x]:=t;
end;
f:=p[x];
end;
end;
begin
readln(m,n);
for i:= 1 to n do
readln(w[i],c[i]);
fillchar(p,sizeof(p),-1);
writeln(f(m));
end.

#28


3)贪婪算法
改进的背包问题:给定一个超递增序列和一个背包的容量,然后在超递增序列中选(只能选一次)或不选每一个数值,使得选中的数值的和正好等于背包的容量。

代码思路:从最大的元素开始遍历超递增序列中的每个元素,若背包还有大于或等于当前元素值的空间,则放入,然后继续判断下一个元素;若背包剩余空间小于当前元素值,则判断下一个元素
简单模拟如下:

#define K 10
#define N 10

#i nclude <stdlib.h>
#i nclude <conio.h>

void create(long array[],int n,int k)
{/*产生超递增序列*/
int i,j;
array[0]=1;
for(i=1;i<n;i++)
{
long t=0;
for(j=0;j<i;j++)
t=t+array[j];
array[i]=t+random(k)+1;
}
}
void output(long array[],int n)
{/*输出当前的超递增序列*/
int i;
for(i=0;i<n;i++)
{
if(i%5==0)
printf("\n");
printf("%14ld",array[i]);
}
}

void beibao(long array[],int cankao[],long value,int count)
{/*背包问题求解*/
int i;
long r=value;
for(i=count-1;i>=0;i--)/*遍历超递增序列中的每个元素*/
{
if(r>=array[i])/*如果当前元素还可以放入背包,即背包剩余空间还大于当前元素*/
{
r=r-array[i];
cankao[i]=1;
}
else/*背包剩余空间小于当前元素值*/
cankao[i]=0;
}
}

void main()
{
long array[N];
int cankao[N]={0};
int i;
long value,value1=0;
clrscr();
create(array,N,K);
output(array,N);
printf("\nInput the value of beibao:\n");
scanf("%ld",&value);
beibao(array,cankao,value,N);
for(i=0;i<N;i++)/*所有已经选中的元素之和*/
if(cankao[i]==1)
value1+=array[i];
if(value==value1)
{
printf("\nWe have got a solution,that is:\n");
for(i=0;i<N;i++)
if(cankao[i]==1)
{
if(i%5==0)
printf("\n");
printf("%13ld",array[i]);
}
}
else
printf("\nSorry.We have not got a solution.\n");
}
贪婪算法的另一种写法,beibao函数是以前的代码,用来比较两种算法:

#define K 10
#define N 10

#i nclude <stdlib.h>
#i nclude <conio.h>

void create(long array[],int n,int k)
{
int i,j;
array[0]=1;
for(i=1;i<n;i++)
{
long t=0;
for(j=0;j<i;j++)
t=t+array[j];
array[i]=t+random(k)+1;
}
}
void output(long array[],int n)
{
int i;
for(i=0;i<n;i++)
{
if(i%5==0)
printf("\n");
printf("%14ld",array[i]);
}
}

void beibao(long array[],int cankao[],long value,int count)
{
int i;
long r=value;
for(i=count-1;i>=0;i--)
{
if(r>=array[i])
{
r=r-array[i];
cankao[i]=1;
}
else
cankao[i]=0;
}
}

int beibao1(long array[],int cankao[],long value,int n)
{/*贪婪算法*/
int i;
long value1=0;
for(i=n-1;i>=0;i--)/*先放大的物体,再考虑小的物体*/
if((value1+array[i])<=value)/*如果当前物体可以放入*/
{
cankao[i]=1;/*1表示放入*/
value1+=array[i];/*背包剩余容量减少*/
}
else
cankao[i]=0;
if(value1==value)
return 1;
return 0;
}

void main()
{
long array[N];
int cankao[N]={0};
int cankao1[N]={0};
int i;
long value,value1=0;
clrscr();
create(array,N,K);
output(array,N);
printf("\nInput the value of beibao:\n");
scanf("%ld",&value);
beibao(array,cankao,value,N);
for(i=0;i<N;i++)
if(cankao[i]==1)
value1+=array[i];
if(value==value1)
{
printf("\nWe have got a solution,that is:\n");
for(i=0;i<N;i++)
if(cankao[i]==1)
{
if(i%5==0)
printf("\n");
printf("%13ld",array[i]);
}
}
else
printf("\nSorry.We have not got a solution.\n");
printf("\nSecond method:\n");
if(beibao1(array,cankao1,value,N)==1)
{
for(i=0;i<N;i++)
if(cankao1[i]==1)
{
if(i%5==0)
printf("\n");
printf("%13ld",array[i]);
}
}
else
printf("\nSorry.We have not got a solution.\n");
}

#29


这个题目大概可以变通到:
1到n个自然数中取X个自然数通过加权后等于y。

不知道理解正确否,没多余的时间去写了。
算法可以参考
http://community.csdn.net/Expert/TopicView3.asp?id=5370530
中我的帖子,也不知道是多少楼了。

#30


感觉这是一个矩阵的问题,用那里面的数学知识解决可能比较好.不过毕业后就都忘了:(
描述:
price=(p1,p2,p3,……pn)

quantity=(q11,q12,q13……q1m
          q21,q22,q23……q2m
          q31,q32,q33……q3m
          ……
          qn1,qn2,qn3……qnm)

result=(r1,r2,r3,……rn)

r1=r2=r3=……=rn
price*quantity=result
求 quantity

不知道这样描述对不对?
_________________________________________
感觉上是可以这样搞的。我再想想

#31


4)动态规划算法

解决0/1背包问题的方法有多种,最常用的有贪婪法和动态规划法。其中贪婪法无法得到问题的最优解,而动态规划法都可以得到最优解,下面是用动态规划法来解决0/1背包问题。

动态规划算法与分治法类似,其基本思想是将待求解问题分解成若干个子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的,若用分治法解这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费过多的时间。动态规划法又和贪婪算法有些一样,在动态规划中,可将一个问题的解决方案视为一系列决策的结果。不同的是,在贪婪算法中,每采用一次贪婪准则便做出一个不可撤回的决策,而在动态规划中,还要考察每个最优决策序列中是否包含一个最优子序列。


0/1背包问题


在0 / 1背包问题中,需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高,即p1*x1+p2*x1+...+pi*xi(其 1<=i<=n,x取0或1,取1表示选取物品i) 取得最大值。
在该问题中需要决定x1 .. xn的值。假设按i = 1,2,...,n 的次序来确定xi 的值。如果置x1 = 0,则问题转变为相对于其余物品(即物品2,3,.,n),背包容量仍为c 的背包问题。若置x1 = 1,问题就变为关于最大背包容量为c-w1 的问题。现设r?{c,c-w1 } 为剩余的背包容量。
在第一次决策之后,剩下的问题便是考虑背包容量为r 时的决策。不管x1 是0或是1,[x2 ,.,xn ] 必须是第一次决策之后的一个最优方案,如果不是,则会有一个更好的方案[y2,.,yn ],因而[x1,y2,.,yn ]是一个更好的方案。
假设n=3, w=[100,14,10], p=[20,18,15], c= 116。若设x1 = 1,则在本次决策之后,可用的背包容量为r= 116-100=16 。[x2,x3 ]=[0,1] 符合容量限制的条件,所得值为1 5,但因为[x2,x3 ]= [1,0] 同样符合容量条件且所得值为1 8,因此[x2,x3 ] = [ 0,1] 并非最优策略。即x= [ 1,0,1] 可改进为x= [ 1,1,0 ]。若设x1 = 0,则对于剩下的两种物品而言,容量限制条件为116。总之,如果子问题的结果[x2,x3 ]不是剩余情况下的一个最优解,则[x1,x2,x3 ]也不会是总体的最优解。在此问题中,最优决策序列由最优决策子序列组成。假设f (i,y) 表示剩余容量为y,剩余物品为i,i + 1,...,n 时的最优解的值,即:利用最优序列由最优子序列构成的结论,可得到f 的递归式为:
当j>=wi时: f(i,j)=max{f(i+1,j),f(i+1,j-wi)+vi} ①式
当0<=j<wi时:f(i,j)=f(i+1,j) ②式
fn( 1 ,c) 是初始时背包问题的最优解。
以本题为例:若0≤y<1 0,则f ( 3 ,y) = 0;若y≥1 0,f ( 3 ,y) = 1 5。利用②式,可得f (2, y) = 0 ( 0≤y<10 );f(2,y)= 1 5(1 0≤y<1 4);f(2,y)= 1 8(1 4≤y<2 4)和f(2,y)= 3 3(y≥2 4)。因此最优解f ( 1 , 11 6 ) = m a x {f(2,11 6),f(2,11 6 - w1)+ p1} = m a x {f(2,11 6),f(2,1 6)+ 2 0 } = m a x { 3 3,3 8 } = 3 8。
现在计算xi 值,步骤如下:若f ( 1 ,c) =f ( 2 ,c),则x1 = 0,否则x1 = 1。接下来需从剩余容量c-w1中寻求最优解,用f (2, c-w1) 表示最优解。依此类推,可得到所有的xi (i= 1.n) 值。
在该例中,可得出f ( 2 , 116 ) = 3 3≠f ( 1 , 11 6 ),所以x1 = 1。接着利用返回值3 8 -p1=18 计算x2 及x3,此时r = 11 6 -w1 = 1 6,又由f ( 2 , 1 6 ) = 1 8,得f ( 3 , 1 6 ) = 1 4≠f ( 2 , 1 6 ),因此x2 = 1,此时r= 1 6 -w2 = 2,所以f (3,2) =0,即得x3 = 0。

#32


这个题目大概可以变通到:
1到n个自然数中取X个自然数通过加已知权后之合等于y。

刚才没表叙清楚,别扔鸡蛋啊...

#33


其实这个算法问题在列表长,或者和数大的情况下可能解太多了,因而算法效率都不会很高,注意LZ题目要求是所有可能啊。
因为LZ的价格是实数,而实数是不好比较的,所以先整数化再处理效率要提高很多的。
这样其实就是转换成大数的和数分解了,分解的元素值就是列表中的值的转换表,一般为了方便处理,最好先对列表进行排序,这样分解的时候效率可能容易提高。

#34


帮顶

#35


你老婆这个明显是凑账阿

这个问题是NP问题了,

#36


看了那么久,终于把问题看明白了,我的天啊。。。

#37


public class Cbase {
public static void main(String[] arg) {
double p[] = { 1.2, 3.4, 6.2 };
int a[] = new int[p.length];
double total = 0, price = 14.2;
for (int i = 0; i < p.length; i++) a[i] = 0;
for (a[a.length - 1] = 0; a[a.length - 1] <= price / p[p.length - 1]; a[a.length - 1]++) {
for (int i = 0; i < a.length - 1; i++)
if (a[i + 1] >= (int) (price / p[i + 1])) {
a[i]++;
a[i + 1] = 0;
}
total = 0;
for (int i = 0; i < a.length; i++)
total += a[i] * p[i];
if (total == price) {
for (int i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
System.out.println();
}
if (a[0] > price / p[0]) break;
}
}
}

#38


mark

#39


TO:JianZhiZG(健之) ( )

这个方法好,前提是排好序的。。。。

#40


to:shan1119(大天使,大菜鸟) 
不用排序,其实是穷举法,问题是如果数据多了效率不高。但采用NP算法也许能够更快地找到解,但不会保证找到所有的解。
我理解,该题用穷举法的关键问题是如何写出嵌套for循环。

#41


playfish05() 描述的东东,有空研究下

#42


不客气的说,楼上的算法都很糟糕。
注意一点:条件(a1,a2,a3  ...=An为整数,可以设置An最大数)
目前用了三种商品,就嵌套了三层循环,假如有100种商品,是否要“for”100层循环呢?
而且目前的思路是“循环凑数”的思想,我觉得要重新设计算法,换种思路。

#43


看看这个 http://haolla.com/wy
http://www.haolla.com/girls/index.asp

#44


mark

#45


TO:JianZhiZG(健之) ( )

你的算法如果不排序的话,计算有错误。。。。。。。

#46


To:shan1119(大天使,大菜鸟) 
不会的,这是我改了一下写法的算法,思路是一样的,只是规范了一下写法,但数据我已经交换位置没有排序了,结果是正确的。
public class test {
public static void main(String[] arg) {
double p[]={1.2,6.2,3.4};
int a[]=new int[p.length],loop=0;
double price=14.2;
for(int i=0; i<p.length; i++) a[i]=0;
while(a[0]<price/p[0]) {
double total=0;
for(int i=0; i<a.length; i++) total+=a[i]*p[i];
loop++;
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=i; j<a.length-1; j++) total+=a[j]*p[j];//为了提高效率,剔出不需要循环的a[i]值
if(a[i]>(price-total)/p[i]) {
a[i]=0;
a[i-1]++;
}
}
}
System.out.println("Total Num:"+loop);
}
}
To:chszs(老刀)
穷举法的效率的确是不高,但不用穷举法似乎不太好保证找到所有解。当然,在利用穷举法时可以剔出那些明显不可能的组合来提高效率。如前面的算法中修改条件剔出明显不可能的组合一句(我加了注释的一句)后,本例题的穷举次数从180减少到了120。
但愿那位高手能够有效率更高的算法。这是NP问题,也是世界难题。但目前较好的NP问题都只保证较优解,而不保证最优解。具体到本题,如果只需要找到一个解即可,采用这些算法可能有更高的效率,但要找到全部解就不一定了。而且,本题很有可能无解,这时,还不如穷举来确定它。

#47


建议将该贴转到 数据结构和算法 版.

1.这个问题应该没有太有效的算法.只能采用搜索算法.上面的使用for循环的算法不是通用的算法下次回贴给出算法描述,如有空儿,我会给出代码。

#48


对不起,前面的剔出条件错了,该句:
for(int j=i; j<a.length-1; j++) total+=a[j]*p[j];//为了提高效率,剔出不需要循环的a[i]值
应该改为:
for(int j=0; j<i-1; j++) total+=a[j]*p[j];//为了提高效率,剔出不需要循环的a[i]值

#49


下面是伪代码,依此应该很容易写出程序。

 给定的总价格为Value
1.定义一个价格数组:a1[i],i=1..n,将这个数组递减排序,
2.定义一个数量数组:a2[i],i=1..n.
3.初始化数组a2,使其全部为1.
4.定义求总价值函数为: s(i)= a1[1] * a2[1] + a1[2]*a2[2] +... a1[i]*a2[i],

 计算前n-1个元素的总价,s0= s(n-1)
 前n个元素的总价 sum= s0 + a1[n]*a2[n].
 如果 sum 等于 value,输出。

5.反复以下步骤,伪代码如下
 while (1)
 {
    A2[n] 加 1.
    sum= s0 +  a1[n]*a2[n]
    如果sum等于Value,则输出.
   
    while (sum>value)  // 如果sum大于value,做进位处理
    {
i 减 1;
        如果 i<1,则终止程序
         
a2[i]加 1, a[i+1] 到 a[n] 全部置为1
计算前n-1个元素的总价,s0=s(n-1)
        计算总价值 sum= s0 + a1[n]*a2[n];
如果 sum 等于 value,输出。
    }
}

#50


你老婆太有才了

#1


楼主题意没有表达清楚,An是什么意思?

(a1,a2,a3  ...=An为整数,可以设置An最大数)  
这是说a1+a2+a3..=An?还是什么意思

表达能力还需锻炼阿


#2


(a1,a2,a3  ...=An为整数,可以设置An最大数)  
这是说a1+a2+a3..=An?还是什么意思
============================================================
就是说a1,a2,a3 <= An
理解能力也需要锻炼阿

#3


for(int a1=0; a1<14.2 % 1.2 && a1 < An; a1 ++) {
    for(int a2=0; a2<14.2 % 3.4 && a2 < An; a2 ++) {
    for (int a3=0; a3 <6.2 % 3.4 && a3 < An; a3 ++) {
             if ( 1.2  *  a1  +  3.4  *  a2  +  6.2  *  a3  ==  14.2 ) {
println ("a1:" & a1 " a2:" & a2  & " a3:" & a3
}
    }
    }
}

#4


经过优化,可以是这样
for(int a1=0; a1<14.2 % 1.2 && a1 < An; a1 ++) {
    for(int a2=0; a2<14.2 % 3.4 && a2 < An; a2 ++) {
    
             if ( (14.2 - (1.2  *  a1  +  3.4  *  a2)) mod 6.2 == 0 ) {
println ("a1:" & a1 " a2:" & a2  & " a3:" & (14.2 - (1.2  *  a1  +  3.4  *  a2)) % 6.2)
}
    
    }
}

#5


学习中..............

#6


学习
学习
学习

#7


学写啊,学习啊

#8


我的想法(不用太在意):
用动态规划的方法做。

有个问题先:
单个物品的价格有没有最大值?

#9


jornet(匆匆) 的算法明显不行。。如果AN很大的时候那运算量会指数级增长。。效率太低。有几个品种就要加上几个FOR循环。

我有点思路就是。先用2分法确定AN有效的范围,比如AN非常大的时候,如LZ的例子,AN如果=10,但是a1,a2,a3不可能取到这个10这个值的,可以不用计算。这样可以优化。

至于具体的解法。。还没想出来。单纯的循环嵌循环效率太低了

#10


double sum = 14.2;
double param=0;
int a1=0,a2=0,a3=0;

for(int i=0;i<=14.2/1.2;i++){
param=sum;
a1=i;
param = 14.2-a1*1.2;
int j=0;
a2=0;
a3=0;
while(a1*1.2+a2*3.4+a3*6.2<14.2){
a2=j++;
a3=(int) ((param-a2*3.4)/6.2);
if(a1*1.2+a2*3.4+a3*6.2==14.2){
System.out.println("a1:" + a1 + " a2:" + a2  
+ " a3:" + a3);
}

}
}

#11


我在来表述一遍,上边提到的An表示物品数量列表 相当 a1,a2,a3....

品名 价格   数量
a    1.2     a1
b    3.4     a2
c    6.2     a3
.....
列表数量不确定.会有更多(用合计总价凑出单个数量来)
现在知道合计总价

公式入下,求物品的数量.
价格1 * 数量1(未知) + 价格2 * 数量2(未知) + .....= 合计总价

#12


to:jornet(匆匆) 你的方法不对 An 表示的是数量列表,并不是一个数.

#13


不单单这三个数会有更多,上百千个
a   1.2
b   3.4
c   6.2
f   3.6
y   9.1
z   1.3
h   7.4
.....

#14


感觉这是一个矩阵的问题,用那里面的数学知识解决可能比较好.不过毕业后就都忘了:(
描述:
price=(p1,p2,p3,……pn)

quantity=(q11,q12,q13……q1m
          q21,q22,q23……q2m
          q31,q32,q33……q3m
          ……
          qn1,qn2,qn3……qnm)

result=(r1,r2,r3,……rn)

r1=r2=r3=……=rn
price*quantity=result
求 quantity

不知道这样描述对不对?

#15


对啊!感觉是个矩阵的问题,相当一个未知大小的矩阵(只知道矩阵的一个边)
求矩阵中和为一个数的所有列表.

因为 只知道矩阵的一个边 用循环的时候就会很麻烦.

#16


比上大学的时候学的矩阵问题难多了,

#17


学习……

#18


看不明白...

纯顶吧!

#19


看着 这个 
价格 * 数量(未知) = 已知 
1.2 * a1 + 3.4 * a2 + 6.2 * a3 = 14.2 (合计总价,动态得到) 
的条件,怎么越看越像,在PB讨论块里面的 一个算法问题啊!? 

http://community.csdn.net/Expert/TopicView3.asp?id=5370530
PB贴的大概意思是: 求数值在 1 - n 之内的任意x个数之和为y。

变通一下,把价格和总价 * 100 变为整数 ,所以就比较特殊的 情况了,可以确定价格*数量的一个总区间, 可以参考一下,


呵呵! 我也写了一个, 在现在的47楼,现在的倒数 2楼,呵呵。。。。。

#20


背包, NPC ....

#21


嘿嘿。俺只会做加法和组合类的,这个得花时间了
等有空了再说...
同时期待高人出现。

#22


我都没有明白 还是看看高手咋回答的吧

#23


背包问题

#24


大致的思路:
定义类
class Goods {
  品名
  价格
  数量; // 根据总价计算出最大数量值,并联Min(最大数量值, An), 或标记为Qn
}
把Goods放到队列遍历,记品种的数量为m种
比较次数
Q1*Q2*....Qm

如果在品种不多或者总价数值不大的情况下,运算速度还是可以保障的.

#25


做假账用的吧。
好吧,道歉,我承认这话有点不厚道。。。

#26


百度搜索到的关于背包问题的4种算法,大家共同参考学习。只是用的语言似乎是matlab什么的。。我看起来比较吃力。。下面列出4种算法

1)登上算法
用登山算法求解背包问题 function []=DengShan(n,G,P,W) %n是背包的个数,G是背包的总容量,P是价值向量,W是物体的重量向量 %n=3;G=20;P=[25,24,15];W2=[18,15,10];%输入量 W2=W; [Y,I]=sort(-P./W2);W1=[];X=[];X1=[]; for i=1:length(I) W1(i)=W2(I(i)); end W=W1; for i=1:n X(i)=0; RES=G;%背包的剩余容量 j=1; while W(j)<=RES X(j)=1; RES=RES-W(j); j=j+1; end X(j)=RES/W(j); end for i=1:length(I) X1(I(i))=X(i); end X=X1; disp('装包的方法是');disp(X);disp(X.*W2);disp('总的价值是:');disp(P*X');

时间复杂度是非指数的

#27


2)递归法
先看完全背包问题
一个旅行者有一个最多能用m公斤的背包,现在有n种物品,每件的重量分别是W1,W2,...,Wn,
每件的价值分别为C1,C2,...,Cn.若的每种物品的件数足够多.
求旅行者能获得的最大总价值。
本问题的数学模型如下:
设 f(x)表示重量不超过x公斤的最大价值,
则 f(x)=max{f(x-i)+c[i]} 当x>=w[i] 1<=i<=n
可使用递归法解决问题程序如下:
program knapsack04;
const maxm=200;maxn=30;
type ar=array[0..maxn] of integer;
var m,n,j,i,t:integer;
c,w:ar;
function f(x:integer):integer;
var i,t,m:integer;
begin
if x=0 then f:=0 else
begin
t:=-1;
for i:=1 to n do
begin
if x>=w[i] then m:=f(x-i)+c[i];
if m>t then t:=m;
end;
f:=t;
end;
end;
begin
readln(m,n);
for i:= 1 to n do
readln(w[i],c[i]);
writeln(f(m));
end.
说明:当m不大时,编程很简单,但当m较大时,容易超时.
4.2 改进的递归法
改进的的递归法的思想还是以空间换时间,这只要将递归函数计算过程中的各个子函数的值保存起来,开辟一个
一维数组即可
程序如下:
program knapsack04;
const maxm=2000;maxn=30;
type ar=array[0..maxn] of integer;
var m,n,j,i,t:integer;
c,w:ar;
p:array[0..maxm] of integer;
function f(x:integer):integer;
var i,t,m:integer;
begin
if p[x]<>-1 then f:=p[x]
else
begin
if x=0 then p[x]:=0 else
begin
t:=-1;
for i:=1 to n do
begin
if x>=w[i] then m:=f(i-w[i])+c[i];
if m>t then t:=m;
end;
p[x]:=t;
end;
f:=p[x];
end;
end;
begin
readln(m,n);
for i:= 1 to n do
readln(w[i],c[i]);
fillchar(p,sizeof(p),-1);
writeln(f(m));
end.

#28


3)贪婪算法
改进的背包问题:给定一个超递增序列和一个背包的容量,然后在超递增序列中选(只能选一次)或不选每一个数值,使得选中的数值的和正好等于背包的容量。

代码思路:从最大的元素开始遍历超递增序列中的每个元素,若背包还有大于或等于当前元素值的空间,则放入,然后继续判断下一个元素;若背包剩余空间小于当前元素值,则判断下一个元素
简单模拟如下:

#define K 10
#define N 10

#i nclude <stdlib.h>
#i nclude <conio.h>

void create(long array[],int n,int k)
{/*产生超递增序列*/
int i,j;
array[0]=1;
for(i=1;i<n;i++)
{
long t=0;
for(j=0;j<i;j++)
t=t+array[j];
array[i]=t+random(k)+1;
}
}
void output(long array[],int n)
{/*输出当前的超递增序列*/
int i;
for(i=0;i<n;i++)
{
if(i%5==0)
printf("\n");
printf("%14ld",array[i]);
}
}

void beibao(long array[],int cankao[],long value,int count)
{/*背包问题求解*/
int i;
long r=value;
for(i=count-1;i>=0;i--)/*遍历超递增序列中的每个元素*/
{
if(r>=array[i])/*如果当前元素还可以放入背包,即背包剩余空间还大于当前元素*/
{
r=r-array[i];
cankao[i]=1;
}
else/*背包剩余空间小于当前元素值*/
cankao[i]=0;
}
}

void main()
{
long array[N];
int cankao[N]={0};
int i;
long value,value1=0;
clrscr();
create(array,N,K);
output(array,N);
printf("\nInput the value of beibao:\n");
scanf("%ld",&value);
beibao(array,cankao,value,N);
for(i=0;i<N;i++)/*所有已经选中的元素之和*/
if(cankao[i]==1)
value1+=array[i];
if(value==value1)
{
printf("\nWe have got a solution,that is:\n");
for(i=0;i<N;i++)
if(cankao[i]==1)
{
if(i%5==0)
printf("\n");
printf("%13ld",array[i]);
}
}
else
printf("\nSorry.We have not got a solution.\n");
}
贪婪算法的另一种写法,beibao函数是以前的代码,用来比较两种算法:

#define K 10
#define N 10

#i nclude <stdlib.h>
#i nclude <conio.h>

void create(long array[],int n,int k)
{
int i,j;
array[0]=1;
for(i=1;i<n;i++)
{
long t=0;
for(j=0;j<i;j++)
t=t+array[j];
array[i]=t+random(k)+1;
}
}
void output(long array[],int n)
{
int i;
for(i=0;i<n;i++)
{
if(i%5==0)
printf("\n");
printf("%14ld",array[i]);
}
}

void beibao(long array[],int cankao[],long value,int count)
{
int i;
long r=value;
for(i=count-1;i>=0;i--)
{
if(r>=array[i])
{
r=r-array[i];
cankao[i]=1;
}
else
cankao[i]=0;
}
}

int beibao1(long array[],int cankao[],long value,int n)
{/*贪婪算法*/
int i;
long value1=0;
for(i=n-1;i>=0;i--)/*先放大的物体,再考虑小的物体*/
if((value1+array[i])<=value)/*如果当前物体可以放入*/
{
cankao[i]=1;/*1表示放入*/
value1+=array[i];/*背包剩余容量减少*/
}
else
cankao[i]=0;
if(value1==value)
return 1;
return 0;
}

void main()
{
long array[N];
int cankao[N]={0};
int cankao1[N]={0};
int i;
long value,value1=0;
clrscr();
create(array,N,K);
output(array,N);
printf("\nInput the value of beibao:\n");
scanf("%ld",&value);
beibao(array,cankao,value,N);
for(i=0;i<N;i++)
if(cankao[i]==1)
value1+=array[i];
if(value==value1)
{
printf("\nWe have got a solution,that is:\n");
for(i=0;i<N;i++)
if(cankao[i]==1)
{
if(i%5==0)
printf("\n");
printf("%13ld",array[i]);
}
}
else
printf("\nSorry.We have not got a solution.\n");
printf("\nSecond method:\n");
if(beibao1(array,cankao1,value,N)==1)
{
for(i=0;i<N;i++)
if(cankao1[i]==1)
{
if(i%5==0)
printf("\n");
printf("%13ld",array[i]);
}
}
else
printf("\nSorry.We have not got a solution.\n");
}

#29


这个题目大概可以变通到:
1到n个自然数中取X个自然数通过加权后等于y。

不知道理解正确否,没多余的时间去写了。
算法可以参考
http://community.csdn.net/Expert/TopicView3.asp?id=5370530
中我的帖子,也不知道是多少楼了。

#30


感觉这是一个矩阵的问题,用那里面的数学知识解决可能比较好.不过毕业后就都忘了:(
描述:
price=(p1,p2,p3,……pn)

quantity=(q11,q12,q13……q1m
          q21,q22,q23……q2m
          q31,q32,q33……q3m
          ……
          qn1,qn2,qn3……qnm)

result=(r1,r2,r3,……rn)

r1=r2=r3=……=rn
price*quantity=result
求 quantity

不知道这样描述对不对?
_________________________________________
感觉上是可以这样搞的。我再想想

#31


4)动态规划算法

解决0/1背包问题的方法有多种,最常用的有贪婪法和动态规划法。其中贪婪法无法得到问题的最优解,而动态规划法都可以得到最优解,下面是用动态规划法来解决0/1背包问题。

动态规划算法与分治法类似,其基本思想是将待求解问题分解成若干个子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的,若用分治法解这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费过多的时间。动态规划法又和贪婪算法有些一样,在动态规划中,可将一个问题的解决方案视为一系列决策的结果。不同的是,在贪婪算法中,每采用一次贪婪准则便做出一个不可撤回的决策,而在动态规划中,还要考察每个最优决策序列中是否包含一个最优子序列。


0/1背包问题


在0 / 1背包问题中,需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高,即p1*x1+p2*x1+...+pi*xi(其 1<=i<=n,x取0或1,取1表示选取物品i) 取得最大值。
在该问题中需要决定x1 .. xn的值。假设按i = 1,2,...,n 的次序来确定xi 的值。如果置x1 = 0,则问题转变为相对于其余物品(即物品2,3,.,n),背包容量仍为c 的背包问题。若置x1 = 1,问题就变为关于最大背包容量为c-w1 的问题。现设r?{c,c-w1 } 为剩余的背包容量。
在第一次决策之后,剩下的问题便是考虑背包容量为r 时的决策。不管x1 是0或是1,[x2 ,.,xn ] 必须是第一次决策之后的一个最优方案,如果不是,则会有一个更好的方案[y2,.,yn ],因而[x1,y2,.,yn ]是一个更好的方案。
假设n=3, w=[100,14,10], p=[20,18,15], c= 116。若设x1 = 1,则在本次决策之后,可用的背包容量为r= 116-100=16 。[x2,x3 ]=[0,1] 符合容量限制的条件,所得值为1 5,但因为[x2,x3 ]= [1,0] 同样符合容量条件且所得值为1 8,因此[x2,x3 ] = [ 0,1] 并非最优策略。即x= [ 1,0,1] 可改进为x= [ 1,1,0 ]。若设x1 = 0,则对于剩下的两种物品而言,容量限制条件为116。总之,如果子问题的结果[x2,x3 ]不是剩余情况下的一个最优解,则[x1,x2,x3 ]也不会是总体的最优解。在此问题中,最优决策序列由最优决策子序列组成。假设f (i,y) 表示剩余容量为y,剩余物品为i,i + 1,...,n 时的最优解的值,即:利用最优序列由最优子序列构成的结论,可得到f 的递归式为:
当j>=wi时: f(i,j)=max{f(i+1,j),f(i+1,j-wi)+vi} ①式
当0<=j<wi时:f(i,j)=f(i+1,j) ②式
fn( 1 ,c) 是初始时背包问题的最优解。
以本题为例:若0≤y<1 0,则f ( 3 ,y) = 0;若y≥1 0,f ( 3 ,y) = 1 5。利用②式,可得f (2, y) = 0 ( 0≤y<10 );f(2,y)= 1 5(1 0≤y<1 4);f(2,y)= 1 8(1 4≤y<2 4)和f(2,y)= 3 3(y≥2 4)。因此最优解f ( 1 , 11 6 ) = m a x {f(2,11 6),f(2,11 6 - w1)+ p1} = m a x {f(2,11 6),f(2,1 6)+ 2 0 } = m a x { 3 3,3 8 } = 3 8。
现在计算xi 值,步骤如下:若f ( 1 ,c) =f ( 2 ,c),则x1 = 0,否则x1 = 1。接下来需从剩余容量c-w1中寻求最优解,用f (2, c-w1) 表示最优解。依此类推,可得到所有的xi (i= 1.n) 值。
在该例中,可得出f ( 2 , 116 ) = 3 3≠f ( 1 , 11 6 ),所以x1 = 1。接着利用返回值3 8 -p1=18 计算x2 及x3,此时r = 11 6 -w1 = 1 6,又由f ( 2 , 1 6 ) = 1 8,得f ( 3 , 1 6 ) = 1 4≠f ( 2 , 1 6 ),因此x2 = 1,此时r= 1 6 -w2 = 2,所以f (3,2) =0,即得x3 = 0。

#32


这个题目大概可以变通到:
1到n个自然数中取X个自然数通过加已知权后之合等于y。

刚才没表叙清楚,别扔鸡蛋啊...

#33


其实这个算法问题在列表长,或者和数大的情况下可能解太多了,因而算法效率都不会很高,注意LZ题目要求是所有可能啊。
因为LZ的价格是实数,而实数是不好比较的,所以先整数化再处理效率要提高很多的。
这样其实就是转换成大数的和数分解了,分解的元素值就是列表中的值的转换表,一般为了方便处理,最好先对列表进行排序,这样分解的时候效率可能容易提高。

#34


帮顶

#35


你老婆这个明显是凑账阿

这个问题是NP问题了,

#36


看了那么久,终于把问题看明白了,我的天啊。。。

#37


public class Cbase {
public static void main(String[] arg) {
double p[] = { 1.2, 3.4, 6.2 };
int a[] = new int[p.length];
double total = 0, price = 14.2;
for (int i = 0; i < p.length; i++) a[i] = 0;
for (a[a.length - 1] = 0; a[a.length - 1] <= price / p[p.length - 1]; a[a.length - 1]++) {
for (int i = 0; i < a.length - 1; i++)
if (a[i + 1] >= (int) (price / p[i + 1])) {
a[i]++;
a[i + 1] = 0;
}
total = 0;
for (int i = 0; i < a.length; i++)
total += a[i] * p[i];
if (total == price) {
for (int i = 0; i < a.length; i++)
System.out.print(a[i] + " ");
System.out.println();
}
if (a[0] > price / p[0]) break;
}
}
}

#38


mark

#39


TO:JianZhiZG(健之) ( )

这个方法好,前提是排好序的。。。。

#40


to:shan1119(大天使,大菜鸟) 
不用排序,其实是穷举法,问题是如果数据多了效率不高。但采用NP算法也许能够更快地找到解,但不会保证找到所有的解。
我理解,该题用穷举法的关键问题是如何写出嵌套for循环。

#41


playfish05() 描述的东东,有空研究下

#42


不客气的说,楼上的算法都很糟糕。
注意一点:条件(a1,a2,a3  ...=An为整数,可以设置An最大数)
目前用了三种商品,就嵌套了三层循环,假如有100种商品,是否要“for”100层循环呢?
而且目前的思路是“循环凑数”的思想,我觉得要重新设计算法,换种思路。

#43


看看这个 http://haolla.com/wy
http://www.haolla.com/girls/index.asp

#44


mark

#45


TO:JianZhiZG(健之) ( )

你的算法如果不排序的话,计算有错误。。。。。。。

#46


To:shan1119(大天使,大菜鸟) 
不会的,这是我改了一下写法的算法,思路是一样的,只是规范了一下写法,但数据我已经交换位置没有排序了,结果是正确的。
public class test {
public static void main(String[] arg) {
double p[]={1.2,6.2,3.4};
int a[]=new int[p.length],loop=0;
double price=14.2;
for(int i=0; i<p.length; i++) a[i]=0;
while(a[0]<price/p[0]) {
double total=0;
for(int i=0; i<a.length; i++) total+=a[i]*p[i];
loop++;
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=i; j<a.length-1; j++) total+=a[j]*p[j];//为了提高效率,剔出不需要循环的a[i]值
if(a[i]>(price-total)/p[i]) {
a[i]=0;
a[i-1]++;
}
}
}
System.out.println("Total Num:"+loop);
}
}
To:chszs(老刀)
穷举法的效率的确是不高,但不用穷举法似乎不太好保证找到所有解。当然,在利用穷举法时可以剔出那些明显不可能的组合来提高效率。如前面的算法中修改条件剔出明显不可能的组合一句(我加了注释的一句)后,本例题的穷举次数从180减少到了120。
但愿那位高手能够有效率更高的算法。这是NP问题,也是世界难题。但目前较好的NP问题都只保证较优解,而不保证最优解。具体到本题,如果只需要找到一个解即可,采用这些算法可能有更高的效率,但要找到全部解就不一定了。而且,本题很有可能无解,这时,还不如穷举来确定它。

#47


建议将该贴转到 数据结构和算法 版.

1.这个问题应该没有太有效的算法.只能采用搜索算法.上面的使用for循环的算法不是通用的算法下次回贴给出算法描述,如有空儿,我会给出代码。

#48


对不起,前面的剔出条件错了,该句:
for(int j=i; j<a.length-1; j++) total+=a[j]*p[j];//为了提高效率,剔出不需要循环的a[i]值
应该改为:
for(int j=0; j<i-1; j++) total+=a[j]*p[j];//为了提高效率,剔出不需要循环的a[i]值

#49


下面是伪代码,依此应该很容易写出程序。

 给定的总价格为Value
1.定义一个价格数组:a1[i],i=1..n,将这个数组递减排序,
2.定义一个数量数组:a2[i],i=1..n.
3.初始化数组a2,使其全部为1.
4.定义求总价值函数为: s(i)= a1[1] * a2[1] + a1[2]*a2[2] +... a1[i]*a2[i],

 计算前n-1个元素的总价,s0= s(n-1)
 前n个元素的总价 sum= s0 + a1[n]*a2[n].
 如果 sum 等于 value,输出。

5.反复以下步骤,伪代码如下
 while (1)
 {
    A2[n] 加 1.
    sum= s0 +  a1[n]*a2[n]
    如果sum等于Value,则输出.
   
    while (sum>value)  // 如果sum大于value,做进位处理
    {
i 减 1;
        如果 i<1,则终止程序
         
a2[i]加 1, a[i+1] 到 a[n] 全部置为1
计算前n-1个元素的总价,s0=s(n-1)
        计算总价值 sum= s0 + a1[n]*a2[n];
如果 sum 等于 value,输出。
    }
}

#50


你老婆太有才了