2021杭电多校第二场 1008 I love exam 动态规划

题意

n n n门课, m m m个课程与成绩与天数的关系,最多复习 T T T天,在挂科数量 ≤ P \le P P的情况下的最大得分。

分析

状态表示
f [ i ] [ j ] f[i][j] f[i][j] 表示第 i i i门课用 j j j天复习能得到的最大分数
d p [ i ] [ j ] [ p ] dp[i][j][p] dp[i][j][p] 表示前 i i i门课花 j j j天挂 p p p门的最大得分

f f f数组使用背包维护
g g g数组:需要枚举当前第 i i i门课的学习天数 k k k

状态转移
( f [ i ] [ k ] < 60 ) (f[i][k]<60) (f[i][k]<60) d p [ i ] [ j ] [ p ] = m a x ( d p [ i ] [ j ] [ p ] , d p [ i − 1 ] [ j − k ] [ p − 1 ] + f [ i ] [ k ] ) dp[i][j][p]=max(dp[i][j][p], dp[i-1][j-k][p-1]+f[i][k]) dp[i][j][p]=max(dp[i][j][p],dp[i1][jk][p1]+f[i][k])
( f [ i ] [ k ] ≥ 60 ) (f[i][k]\ge 60) (f[i][k]60) d p [ i ] [ j ] [ p ] = m a x ( d p [ i ] [ j ] [ p ] , d p [ i − 1 ] [ j − k ] [ p ] + f [ i ] [ k ] ) dp[i][j][p]=max(dp[i][j][p], dp[i-1][j-k][p]+f[i][k]) dp[i][j][p]=max(dp[i][j][p],dp[i1][jk][p]+f[i][k])

代码

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iomanip>
#include <map>
#include <cstdio>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
#define endl '\n'
ll gcd(ll a, ll b){
    return b == 0 ? a : gcd(b, a % b);
}
void input(){
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
}
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*f;
}
const int N = 1e6+10, M = N * 2, inf = 1e8;
const int maxke = 60, maxt = 510, maxgua = 4;
int f[maxke][maxt]; // 第i门课花j天最大得分
int dp[maxke][maxt][maxgua]; // 前i门课花j天挂p门最大得分
map<string, int> mp;
vector<pii> a[maxke]; // {得分,天数}
int t, n, m;
int T, P;
void init(){
    mp.clear();
    memset(f, -0x3f, sizeof(f));
    memset(dp, -0x3f, sizeof(dp));
    for(int i = 0; i < maxke; i++) a[i].clear();
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
   //input();
    cin>>t;
    while(t--){
        init();
        cin>>n;
        int id = 1;
        for(int i = 1; i <= n; i++){
            string s; cin>>s; mp[s] = id++;
        }
        cin>>m;
        for(int i = 1; i <= m; i++){
            string s; int a1, b; cin>>s>>a1>>b;
            a[mp[s]].push_back(make_pair(a1, b));
        }
        cin>>T>>P;
        for(int i = 0; i <= n; i++) f[i][0] = 0;
        for(int x = 1; x <= n; x++)
            for(int i = 0; i < a[x].size(); i++)
                for(int j = T; j >= a[x][i].second; j--)
                    f[x][j] = min(100, max(f[x][j],f[x][j-a[x][i].second]+a[x][i].first));

        dp[0][0][0] = 0;
        for(int i = 1; i <= n; i++) // i门课
            for(int j = 0; j <= T; j++) // 天数
                for(int p = 0; p <= P; p++) // 挂几门
                    for(int k = 0; k <= j; k++) // 当前课几天学
                        if(f[i][k] < 60 && p != 0) dp[i][j][p] = max(dp[i][j][p], dp[i-1][j-k][p-1] + f[i][k]);
                        else if(f[i][k] >= 60) dp[i][j][p] = max(dp[i][j][p], dp[i-1][j-k][p] + f[i][k]);
                
        int ans = -1;
        for(int p = 0; p <= P; p++) ans = max(ans, dp[n][T][p]);
        cout<<ans<<endl;
    }
    return 0;
}

比赛时没想到思路,还是队友给力。。。要多练练了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值