i love exam

该文是一个编程题目的解题思路,涉及动态规划算法。题目描述了一个学生有若干场考试,一定数量的复习资料,每份资料对应不同分数提升和学习时间。目标是在不超过允许挂科数量的情况下,找到最大总分。解题方法是通过两个维度的动态规划数组计算,在有限时间内优化考试得分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:
https://vjudge.net/contest/541856#problem/H
题意:
有n场考试,还有t天开学
有m本复习资料
对于第i本复习资料,名称是s[i],研究的时间是y[i],可以在这门学科上加x[i]的分(每科的上限是100,每本资料只能用一次)
他的所有科目都是0分,可以挂p门课,否则就要被叫家长
想知道在不叫家长的情况下能得到的最大分,如果被叫了家长输出-1
数据范围:n<=50,m<=15000,s[i]长度不超过15,x[i]和y[i]数据范围是110,天数t:1500,允许不及格科目p:0<=3
思路:
f[i][j]表示第i门课程花费时间不超过j能得到的最大分数
先用一个vector< pii> a[i]来存第i门课程的所有书籍
那么枚举第i门的每个书籍x,每本都有选或者不选的情况,选x的状态转移是:
f[i][j]=max(f[i][j],f[i][j-v[x]]+w[x]);
dp[i][j][pp]表示在前i科里,花费不超过j天的时间,挂了pp门课的最大分数。
枚举第i门课的最大花费时间k,然后得到这个情况的最大分数f[i][k]
当f[i][k]>=60的时候状态转移方程是:dp[i][j][pp]=max(dp[i][j][pp],dp[i-1][j-k][pp]+f[i][k]);
当f[i][k]<=60的时候且pp-1>=0的时候的状态转移方程是:dp[i][j][pp]=max(dp[i][j][pp],dp[i-1][j-k][pp-1]+f[i][k]);

#include<bits/stdc++.h>
#include<vector>
#define v first
#define w second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int n,m,t,p;
int f[60][600];
int dp[60][600][4];
vector<pii> a[60];
map<string,int> mp;
void sove(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		string s;
		cin>>s;
		mp[s]=i;
		a[i].clear();
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		string s;
		cin>>s;
		int id=mp[s];
		int v,w;
		scanf("%d%d",&w,&v);
		a[id].push_back({v,w});
	}
	scanf("%d%d",&t,&p);
	memset(f,0,sizeof f);
	for(int i=1;i<=n;i++){
		for(auto vv:a[i]){
			int vx=vv.v,wx=vv.w;
			for(int j=t;j>=vx;j--){
				f[i][j]=max(f[i][j],f[i][j-vx]+wx);
				f[i][j]=min(100,f[i][j]);
			}
		}
	}
	memset(dp,-0x3f,sizeof dp);
	dp[0][0][0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=t;j++){
			for(int k=0;k<=j;k++){
				for(int pp=0;pp<=p;pp++){
					if(f[i][k]>=60){
						dp[i][j][pp]=max(dp[i][j][pp],dp[i-1][j-k][pp]+f[i][k]);
					}else if(pp-1>=0){
						dp[i][j][pp]=max(dp[i][j][pp],dp[i-1][j-k][pp-1]+f[i][k]);
					}
				}
			}
		}
	}
	int ans=-1;
	for(int i=0;i<=p;i++){
		ans=max(dp[n][t][i],ans);
	}
	printf("%d\n",ans);
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		sove();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值