hdu 4091 线性规划

分析转自:http://blog.csdn.net/dongdongzhang_/article/details/7955136

题意 :  背包能装体积为N,  有两种宝石, 数量无限, 不能切割。  分别为 size1   value 1 size2 value2

问背包能装最大的价值?


思路 : 线性规划问题。  有一组坑爹数据  100 3 3 7 7   一般的会输出 99     但是结果是 100  各10颗


线性规划知识, x, y 分别为 取两种宝石的数量   目标函数 : z = v1 * x + v 2 * y;      K = -(v1 / v2);

1.   x >= 0;

2.   y >= 0;

3.   s1 * x + s2 + y <= N;   k = - (s1 / s2);




若  abs(K)  > abs (k)  那么 将相交与B。   若abs(K) ==  abs(k)  整条直线都可以。 若 abs(K) < abs(k) 相交与A

其实   abs(K) = v1 / v2  >  abs(k) = s1 / s2   正好是 价值比的比较,   v1 / s1 > v2 / s2    ,v1价值大, 就应该  x  大些, 取1宝石多些。

同理  价值相同  就应该 x, y 取什么都可以,  v2 价值大, 就应该 y 大些,  取2宝石多些。


但是  宝石不能切割, 所以。 就形成了一个区域, 在最优解附近。 所以区域附近的点 需要枚举。

不过有一个不变的是, 在两宝石的体积的最小公倍数内, 肯定取价值大。

而在最小公倍外的,就要分别枚举。 不能盲目的取价值大。 

 比如一个例子,   20 4 5 6 8   答案是 26  = 2 * 5 + 2 * 8。  若只取价值大的, 会装不满。 没取到最优解。    

4 与 6 的最小公倍数是 12.  那每一个12的体积  就应该取  2个  宝石2   因为宝石2价值大。

剩余的8 就有取枚举, 0 * 5 + 1 * 6 , 或者  1 * 5 + 0 * 6,  或者 2 * 5 + 0 * 6   那么就取2个宝石1.  就能装满了, 并且价值最大。

但是 如果是 15 4 5 6 8 的话,  那么按照这方法就会输出   16   只能取到  2个 宝石2  剩余3体积, 不能取到任意宝石。 

答案应该是 18 = 2 * 5 + 1 * 8,   少取一个宝石2,腾出6体积,并 利用剩余的3体积的2体积 取两颗宝石1,价值更大。

所以,面对这问题。  我们就应该至少腾出一个公倍数的空间才枚举。  不然就会出错。

 1 #include<stdio.h>
 2 #include<algorithm>
 3 using namespace std;
 4 long long gcd(long long da,long long xiao)
 5 {
 6     long long temp;
 7     while(xiao!=0)
 8     {
 9         temp=da%xiao;
10         da=xiao;
11         xiao=temp;
12     }    
13     return da;
14 }    
15 int main()
16 {
17     int iCase=0;
18     int T;
19     scanf("%d",&T);
20     long long N,S1,V1,S2,V2;
21     while(T--)
22     {
23         iCase++;
24         scanf("%I64d%I64d%I64d%I64d%I64d",&N,&S1,&V1,&S2,&V2);
25         long long tmp=S1*S2/gcd(S1,S2);
26         long long res;
27         long long tt=N/tmp;
28         N=N%tmp;
29         if(tt)
30         {
31             tt--;
32             N+=tmp;
33         }    
34         res=max((tt)*(tmp/S1)*V1,(tt)*(tmp/S2)*V2);
35         long long res2=0;
36         if(S2>S1)
37         {
38             long long t;
39             t=S1;S1=S2;S2=t;
40             t=V1;V1=V2;V2=t;
41         }    
42         for(int i=0;i<=N/S1;i++)
43         {
44             if(res2<i*V1+(N-i*S1)/S2*V2)res2=i*V1+(N-i*S1)/S2*V2;
45         }    
46         res+=res2;
47         printf("Case #%d: %I64d
",iCase,res);
48     }    
49     return 0;
50 }
原文地址:https://www.cnblogs.com/cnblogs321114287/p/4286913.html