一道很好的dp题目,首先考虑普通的背包做法,dp[ i ][ j ][ k ]表示枚举到第i个物品,糖度不超过j,咸度不超过k时最大能选多少物品,显然时间复杂度超了。
TLE代码:
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5+5;
int n,ex,ey;
int a[N],b[N];
int dp[10005][10005];
void solve(){
cin>>n>>ex>>ey;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
}
for(int i=1;i<=n;i++){
for(int j=ex;j>=a[i];j--){
for(int k=ey;k>=b[i];k--){
dp[j][k] = max(dp[j][k],dp[j-a[i]][k-b[i]]+1);
}
}
}
cout<<min(n,dp[ex][ey]+1)<<"\n";
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
while(T--){
solve();
}
return 0;
}
因此我们可以转换一下思路,dp[ i ][ j ][ k ]表示枚举到第i个物品,前面选了j个物品,在满足糖度小于等于k的情况下,咸度的最小值。
AC代码:
#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5+5;
int n,ex,ey;
int a[N],b[N];
int dp[105][105][10005];///枚举到第i个,选了j个,糖度为k的情况下咸度的最小值
void solve(){
cin>>n>>ex>>ey;
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];
}
int ans = 0;
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++){
for(int k=0;k<=ex;k++){
dp[i][j][k] = inf;
if(i-1>=j){
dp[i][j][k] = dp[i-1][j][k];
}
if(j-1>=0&&k>=a[i]){
dp[i][j][k] = min(dp[i][j][k],dp[i-1][j-1][k-a[i]]+b[i]);
}
if(dp[i][j][k]<=ey)ans = max(ans,j);
}
}
}
cout<<min(ans+1,n)<<"\n";
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T=1;
while(T--){
solve();
}
return 0;
}