Codeforces 366C Dima and Salad:揹包dp

Leohh發表於2018-01-03

題目連結: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 }

 

相關文章