Difficulty Level : Easy-Medium
Required Knowledge : DP, Knapsack Problem
Problem Setter : Devendra Agarwal
Problem Tester : Cao Peng
Approach
Let us assume X is the maximum profit Mr. Dorsey can make by selling gold for i passengers.
Once this is done for calculating for i passengers, it can be extended to calculate for (i+1)th passenger. How?
Say the (i+1)th passenger offered Dorsey $v in exchange for âaâ grams of gold,then recalculate it by taking two possibilities , i.e. either to take the value offered by the (i+1)th passenger or to not take the value offered by the (i+1)th passenger So the formula becomes:
for ( j=a;j<=X;j++)
dp[j]=max(dp[j],dp[j-a]+v)
And after Mr. Dorsey has enquired all the passengers ,then he can get to know his maximum profit by dp[X]
Time Complexity
The time complexity is given by NX here.
The time complexity can be further reduced.
If you notice that as max(X) ⤠5000 , so you only need to store highest (5000/i) values for i gram gold. So â(5000/i) = 43376 and thus the worst time complexity reduces to 43376X + Sorting Time
Setterâs Code
#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
#define INF (1<<30)
typedef long long int ll;
typedef struct Point Pt;
struct Point
{
int v,wt;
bool operator<(const Pt t)const
{
if(t.v<v)
return 1;
else
return 0;
}
}input[1000001];
vector<int> myvector[5001]; //max x is 5000
int size[5001]; //max x is 5000
ll dp[5001]; //max x is 5000
ll max(ll a,ll b)
{
if(a>b) return a;
else return b;
}
int main()
{
int N,x,y,value;
scanf("%d%d",&N,&x);
for(int i=0;i<N;i++) scanf("%d%d",&input[i].v,&input[i].wt);
sort(input,input+N); //sorting by decreasing value.
memset(size,0,sizeof(size));
for(int i=0;i<N;i++){
y=input[i].wt;
if(y>x) continue;
else if(size[y]>x/y) continue; //stroing only the best x/y amounts for each y
else{
myvector[y].push_back(input[i].v);
size[y]++;
}
}
//memset(dp,0,sizeof(dp));
for(int i=1;i<=x;i++) dp[i]=-(ll)1000000000*(ll)100000000;
dp[0]=0;
for(int i=1;i<=x;i++){
while(!myvector[i].empty()){
value=myvector[i].back();
for(int j=x;j>=i;j--){
if(dp[j-i]>=0)
dp[j]=max(dp[j],dp[j-i]+(ll)value);
}
myvector[i].pop_back();
}
}
if(dp[x]>=0) printf("%lld\n",dp[x]);
else printf("Got caught!");
return 0;
}
Testerâs Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
using namespace std;
long long dp[5002];
vector<int> have[5002];
void better(long long &x,long long y,long long z) {
if ((y >= 0) && (z >= 0) && (y + z > x)) {
x = y + z;
}
}
int main() {
int i,j,k,m,n,x,y;
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
scanf("%d%d",&n,&m);
assert(n >= 1 && n <= 1000000);
assert(m >= 1 && m <= 5000);
memset(dp,0xff,sizeof(dp));
for(dp[0] = 0;n;--n) {
scanf("%d%d",&x,&y);
assert(x >= 1 && x <= 1000000);
assert(y >= 1 && y <= 1000000);
if (y == 0) {
if (x > 0) {
dp[0] += x;
}
continue;
}
if (y > m) {
continue;
}
have[y].push_back(x);
}
for (i = 1; i <= m; ++i) {
if (!have[i].empty()) {
sort(have[i].begin(),have[i].end());
for (j = min((int) have[i].size(), m / i); j ; --j) {
for (k = m; k >= i; --k) {
better(dp[k], dp[k - i], have[i][have[i].size() - j]);
}
}
}
}
if (dp[m] >= 0) {
printf("%lld\n",dp[m]);
}
else {
puts("Got caught!");
}
return 0;
}