转自:http://blog.csdn.net/a601025382s/article/details/12308193
题意:
输入背包体积n,绿宝石体积s1,价值v1,蓝宝石体积s2,价值v2,宝石数目无限,问背包里能放下的最大价值?
题解:
看过去很像完全背包,可数据很大(虽然没给出,也能猜到,不然太水了),所以不能用背包求。又只有两种物品,想到了贪心,将价值与体积比大(称为价值比)的优先放入。但体积限制,这样还不可以,还需要枚举减少价值比大的宝石个数,是否可以增大所求价值。又我们可以知道对于体积是m=lcm(s1,s2)背包,肯定全选价值比大的。所以至多只要枚举n-n/m+m的体积。如果小于这个值,存在大于m的空余,这个空余肯定用价值大的放置。
注意:
1.不够一个公倍数的时候,计算需要小心。。我就出错了。。
2.枚举的时候,跨度选择max(s1,s2),这个算是优化吧,没有的话会TLE
1 #include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 #include<map> 9 #include<set> 10 #include<string> 11 //#include<pair> 12 13 #define N 10000005 14 #define M 1005 15 #define mod 1000000007 16 //#define p 10000007 17 #define inf 0x3f3f3f3f 18 #define mod2 100000000 19 #define ll long long 20 #define LL long long 21 #define maxi(a,b) (a)>(b)? (a) : (b) 22 #define mini(a,b) (a)<(b)? (a) : (b) 23 24 using namespace std; 25 26 ll n,s1,v1,s2,v2; 27 ll ans; 28 ll ma; 29 ll g; 30 ll c1,c2; 31 ll ans1,ans2; 32 33 ll gcd(ll a,ll b) 34 { 35 return b==0?a:gcd(b,a%b); 36 } 37 ll lcm(ll a,ll b) 38 { 39 return a/gcd(a,b)*b; 40 } 41 42 void ini() 43 { 44 ans=0; 45 ans1=ans2=0; 46 scanf("%I64d%I64d%I64d%I64d%I64d",&n,&s1,&v1,&s2,&v2); 47 g=lcm(s1,s2); 48 c1=g/s1; 49 c2=g/s2; 50 } 51 52 53 54 void solve() 55 { 56 if(n/g>=1) 57 ans1=(n/g-1)*max(c1*v1,c2*v2); 58 ll i; 59 if(s1<s2){ 60 swap(c1,c2); 61 swap(s1,s2); 62 swap(v1,v2); 63 } 64 ll left=n%g; 65 if(n/g>=1) 66 left+=g; 67 ll en=left/s1; 68 ll re; 69 for(i=0;i<=en;i++){ 70 re=i*v1+(left-i*s1)/s2*v2; 71 ans2=max(ans2,re); 72 } 73 ans=ans1+ans2; 74 } 75 76 void out() 77 { 78 printf("%I64d\n",ans); 79 } 80 81 int main() 82 { 83 int T; 84 //freopen("data.in","r",stdin); 85 //freopen("data.out","w",stdout); 86 scanf("%d",&T); 87 for(int ccnt=1;ccnt<=T;ccnt++) 88 // while(T--) 89 // while(scanf("")) 90 { 91 //if(n==0 && k==0 ) break; 92 93 ini(); 94 solve(); 95 printf("Case #%d: ",ccnt); 96 out(); 97 } 98 99 return 0; 100 }