hdu2 1008 I love exam 背包+dp

21 篇文章 0 订阅

题意:求一个学生在最多挂P门课程的情况下,有T天时间让他复习课程,有n门课程,m本复习材料,问他能取得的最高分数是多少。

  • 注意:没有满足条件的情况出现,要输出-1,没看到这句wa了好几发…

思路:

  • 状态表示
    f [ i ][ j ] 表示第 i 门课用 j 天复习能得到的最多分数
    dp[ i ][ j ][ k ] 表示前 i 门课花 j 天挂 k 门的最多分数
    f[ ] 数组使用背包维护
    dp[ ][ ][ ]数组:需要枚举当前第 i 门课的学习天数 k

  • 状态转移
    (当 f [ i ][ z ] < 60 ) dp[ i ][ j ][ k ] = max(dp[ i ][ j ][ k ], dp[ i - 1][ j - z ][ k - 1] + f[ i ][ z ])
    ( 当f [ i ][ k ] >= 60 ) dp[ i ][ j ][ k ] = max(dp[ i ][ j ][ k ], dp[ i - 1][ j - z][ k ] + f[ i ][ z ])

  • 该题包含很多小细节需注意

accode:

#include<iostream>
#include<cstdio>
#include<cstring>
#include <string>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
map<string,int> s;
//f[i][j]:第i门课程花费j天能取得的最高分数
//dp[i][j][k]:在挂k门的情况下,i门课程复习j天的最高分数
int f[55][550];
int dp[55][550][5];
typedef pair<int,int> pll;
//map会对插入的元素按键自动排序,而且不允许键重复。
//vector<pair<int, int>>这种用法不会自动排序,而且允许重复。
inline int max(int a, int b){return (a > b) ? a : b;} 
inline int min(int a, int b){return (a < b) ? a : b;}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    int t, n, m, x, y, T, P;
    string str;
    scanf("%d", &t);
    while(t--)
    {
        s.clear();
        vector<pll> q[55];
        memset(f,-0x3f,sizeof f);
        memset(dp,-0x3f,sizeof dp);
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            cin>>str;
            s[str] = i;
        }
           scanf("%d", &m);
        for(int i = 1; i <= m; i++)
        {
            cin>>str>>x>>y;
            q[s[str]].push_back({x, y});
        }
        scanf("%d %d", &T, &P);
        for(int i = 1; i <= n; i++)    f[i][0] = 0;//初始化 
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j < q[i].size(); j++)//注意从0开始 
            {
                for(int k = T; k >= q[i][j].second; k--)//从大到小,花费k天复习材料 
                {//f[]数组用背包维护 
                    f[i][k]=min(100,max(f[i][k],f[i][k-q[i][j].second]+q[i][j].first));
                }
            }
        }
        dp[0][0][0]=0;
        //前三维对应 n, T, P 
        for(int i=1;i<=n;i++)//第几门课
        {
            for(int j=0;j<=T;j++)//学习天数 
            {
                for(int k=0;k<=P;k++)//挂几门课
                {
                    for(int z=0;z<=j;z++)//该课程学习天数 
                    {
                        if(f[i][z]<60&&k!=0)//注意此处的 k != 0
                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-z][k-1]+f[i][z]);
                        else if(f[i][z]>=60)
                            dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-z][k]+f[i][z]);

                    }
                }
            }
        }
        int ans = -1;
        for(int i = 0; i <= P; i++)
            ans = max(ans, dp[n][T][i]);
        cout<<ans<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值