【2021杭电多校第二场】 2021“MINIEYE杯”中国大学生算法设计超级联赛(2) I love exam (背包dp好题)
-
题意:有\(n\)门课需要复习,每门课有\(m\)本资料,花费\(y\)时间可以是这门课得到\(x\)分,60分及格,剩下\(t\)时间,假设所有课现在不看资料去考试都是\(0\)分,问你在最多挂\(p\)门的情况下,总分最多能有多少,或者最少挂不止\(p\)门,输出\(-1\).
-
题解:对于每门课,先背包求出花费时间能得到的最多分数,然后设\(dp[i][j][g]\)表示,前\(i\)门课花费\(j\)时间挂\(g\)门最多能得多少分,分挂还是没挂再背包转移一下即可。
-
代码:
#include <bits/stdc++.h> #define ll long long #define fi first #define se second #define pb push_back #define me memset #define rep(a,b,c) for(int a=b;a<=c;++a) #define per(a,b,c) for(int a=b;a>=c;--a) const int N = 1e6 + 10; const int mod = 1e9 + 7; const int INF = 0x3f3f3f3f; using namespace std; typedef pair<int,int> PII; typedef pair<ll,ll> PLL; ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;} ll lcm(ll a,ll b) {return a/gcd(a,b)*b;} int n,m; string s; struct node{ int fi,se; }; vector<node> a[500]; int x,y; int t,p; int f[2000]; int dp[55][1000][20]; map<string,int> mp; int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); int _; cin>>_; while(_--){ cin>>n; rep(i,1,n){ cin>>s; mp[s]=i; } cin>>m; rep(i,1,m){ cin>>s; cin>>x>>y; a[mp[s]].pb({x,y}); } cin>>t>>p; me(dp,-0x3f,sizeof(dp)); dp[0][0][0]=0; for(int i=1;i<=n;++i){ me(f,-INF,sizeof(f)); f[0]=0; for(int k=0;k<(int)a[i].size();++k){ for(int j=t;j>=a[i][k].se;--j){ f[j]=max(f[j],f[j-a[i][k].se]+a[i][k].fi); f[j]=min(100,f[j]); } } for(int l=1;l<=t;++l){ for(int j=l;j<=t;++j){ for(int g=0;g<=p;++g){ if(f[l]<0) continue; if(f[l]<60){ if(g) dp[i][j][g]=max(dp[i][j][g],dp[i-1][j-l][g-1]+f[l]); } else dp[i][j][g]=max(dp[i][j][g],dp[i-1][j-l][g]+f[l]); } } } } int ans=-INF; for(int j=0;j<=t;++j){ for(int g=0;g<=p;++g){ ans=max(ans,dp[n][j][g]); } } if(ans<0) cout<<-1<<'\n'; else cout<<ans<<'\n'; mp.clear(); for(int i=1;i<=n;++i) a[i].clear(); } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮