分析轉自: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\n",iCase,res); 48 } 49 return 0; 50 }
?