Codeforces 366C Dima and Salad:背包dp
题目链接:http://codeforces.com/problemset/problem/366/C
题意:
有n个物品,每个物品有两个属性a[i]和b[i]。
给定k,让你选出一些物品,使得 ∑ a[i] / ∑ b[i] = k。
问你选出物品的 ∑ a[i]最大是多少。
题解:
将原式变形:
∑ a[i] - k * ∑ b[i] = 0
可以看做有一个容积为0的箱子,每个物品的价值为a[i],体积为a[i] - k*b[i],问你最大总价值。
这就变成了01背包。
但是体积a[i] - k*b[i]有可能为负值。
所以将体积为正的分一堆,体积为负的分到另一堆。
体积取绝对值,分别跑一遍01背包求出pos数组和neg数组。
pos[i]和neg[i]分别表示用了i的体积,此时的最大总价值。
然后统计答案。
枚举花费体积i,正负相互抵消:ans = max(pos[i] + neg[i])
当ans = 0时说明啥都没选,输出-1。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 105 5 #define MAX_C 100005 6 7 using namespace std; 8 9 int n,k; 10 int a[MAX_N]; 11 int b[MAX_N]; 12 int pos[MAX_C]; 13 int neg[MAX_C]; 14 15 void read() 16 { 17 cin>>n>>k; 18 for(int i=1;i<=n;i++) cin>>a[i]; 19 for(int i=1;i<=n;i++) cin>>b[i]; 20 } 21 22 void work() 23 { 24 memset(pos,0xc0,sizeof(pos)); 25 memset(neg,0xc0,sizeof(neg)); 26 pos[0]=neg[0]=0; 27 for(int i=1;i<=n;i++) 28 { 29 int c=a[i]-k*b[i]; 30 if(c>=0) 31 { 32 for(int j=MAX_C-1;j>=c;j--) 33 { 34 pos[j]=max(pos[j],pos[j-c]+a[i]); 35 } 36 } 37 else 38 { 39 c=-c; 40 for(int j=MAX_C-1;j>=c;j--) 41 { 42 neg[j]=max(neg[j],neg[j-c]+a[i]); 43 } 44 } 45 } 46 int ans=0; 47 for(int i=0;i<MAX_C;i++) 48 { 49 ans=max(ans,pos[i]+neg[i]); 50 } 51 if(ans) cout<<ans<<endl; 52 else cout<<-1<<endl; 53 } 54 55 int main() 56 { 57 read(); 58 work(); 59 }