I love exam(背包,动态规划)

先放代码,一会补
这道题是一个用01背包问题改的一道题目,因为这道题目问的是n门课在m时间内可以挂k门课最高可以得到的总分数,所以我们很容易可以想到开一个三维数组dp[i][j][k]来表示前i门课在j分钟内挂k门课所获得的的最大分数。
这里我们再开一个数组f[i][j]来表示第i门课用j分钟所能获得的最大分数。
初始化:
dp[0][0][0] = 0;//前0门课用0分钟挂0科所获的分数理所当然是0
f[i][0] = 0;//一门课花0分钟所获得的分数也应当是0

1、对科目名称进行映射

这里我们用map就很好解决

for(int i=1;i<=n;i++){
	string s;
	cin >> s;
	km[s] = i;
}

这样之后我们在后面处理每一门课的时候就可直接查找得到相应科目的ID序列号,例如我们有一个科目的名称是字符串s,我们就可以直接通过km[s]来得到相应的科目编号,之后再用vector把每一科所对应的复习资料push_back到后面即可。

struct infor{
	int val;
	int time;
};
vector<infor>cour[60];

for(int i=0;i<m;i++){
	string s;
	cin >> s;
	int id = km[s];
	infor a;
	cin >> a.val >> a.time;
	cour[id].push_back(a);
}

2、对01背包进行修改

首先我们用01背包的思想处理每一门课的时间,然后再用动态转移方程求得最优解:

dp[i][k][lim] = max(dp[i][k][lim], dp[i-1][k-j][lim-flag] + f[i][j]);
//复习用的总时间减去复习这门课所用的时间就是剩余课复习的时间,这段时间取dp加上复习这门课所取得的的成绩
//如果这门课没有及格,那么就是lim-1,如果这门课及格了,就仍然是lim,这里用flag标记一下就可以很好的处理。

最后遍历一下找出最高成绩的解即可

	int ans = -0x3f3f;
	for(int i=0;i<=t;i++){
		for(int j=0;j<=p;j++){
			ans = max(ans,dp[n][i][j]);//因为可以获得的最大分数,所以挂科的数目不确定,遍历即可
		}
	}
	if(ans < 0) cout << -1 << endl;//不能满足条件,输出-1
	else cout << ans << endl;
for(int i=1;i<=n;i++){
	//先做一步初始化		
	f[i][0] = 0;//时间为0 得到的分数是0 
	//裸的01背包,在t分钟之内所能得到的最大分数		
	for(int j = 0;j < cour[i].size();j++){
		for(int k = t;k >= cour[i][j].time;k--){
			f[i][k] = max(f[i][k],f[i][k - cour[i][j].time] + cour[i][j].val);
		}
	}
			
//	for(int j=1;j<=t;j++) f[i][j] = max(f[i][j],f[i][j-1]);
			
	for(int j = 1;j <= t; j++){//分给这门课的时间
		for(int k = j;k <= t; k++){//复习用的总时间
			for(int lim = 0;lim <= p;lim++){//挂科的数目
				if(f[i][j]<0) continue;
				int flag = 0;//是否挂科
				if(f[i][j] < 60) flag = 1;//挂科则标记为1
				if(f[i][j] > 100) f[i][j] = 100;///最高分是100
				if(lim >= flag) //可以挂科
					dp[i][k][lim] = max(dp[i][k][lim], dp[i-1][k-j][lim-flag] + f[i][j]);
			}
		}
	}
	int ans = -0x3f3f;
	for(int i=0;i<=t;i++){
		for(int j=0;j<=p;j++){
			ans = max(ans,dp[n][i][j]);//因为可以获得的最大分数,所以挂科的数目不确定,遍历即可
		}
	}
	if(ans < 0) cout << -1 << endl;
	else cout << ans << endl;
}

完整代码如下:

#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
map<string,int>km;
struct infor{
	int val;
	int time;
};
vector<infor>cour[60];
int dp[60][3000][5];//dp[i][j][k]:前i门课用j分钟挂k科的最大分数
int f[60][3000];//f[i][j]:第i门课用j分钟所得到的最大分数 
int main(){
	int T;
	cin >> T;
	while(T--){
		int n;
		cin >> n;
		km.clear();
		for(int i=1;i<=51;i++){
			cour[i].clear();
		} 
		for(int i=1;i<=n;i++){
			string s;
			cin >> s;
			km[s] = i;
		}
		
		int m;
		cin >> m;
		for(int i=0;i<m;i++){
			string s;
			cin >> s;
			int id = km[s];
			infor a;
			cin >> a.val >> a.time;
			cour[id].push_back(a);
		}
		int t,p;
		cin >> t >> p;
		memset(f,-0x3f3f,sizeof(f));
		memset(dp,-0x3f3f,sizeof(dp));
		dp[0][0][0] = 0;
		for(int i=1;i<=n;i++){
			
			f[i][0] = 0;//时间为0 得到的分数是0 
			
			for(int j = 0;j < cour[i].size();j++){
				for(int k = t;k >= cour[i][j].time;k--){
					f[i][k] = max(f[i][k],f[i][k - cour[i][j].time] + cour[i][j].val);
				}
			}
			
//			for(int j=1;j<=t;j++) f[i][j] = max(f[i][j],f[i][j-1]);
			
			for(int j = 1;j <= t; j++){
				for(int k = j;k <= t; k++){
					for(int lim = 0;lim <= p;lim++){
						if(f[i][j]<0) continue;
						int flag = 0;
						if(f[i][j] < 60) flag = 1;
						if(f[i][j] > 100) f[i][j] = 100;
						if(lim >= flag) 
							dp[i][k][lim] = max(dp[i][k][lim], dp[i-1][k-j][lim-flag] + f[i][j]);
					}
				}
			}
		
		int ans = -0x3f3f;
		for(int i=0;i<=t;i++){
			for(int j=0;j<=p;j++){
				ans = max(ans,dp[n][i][j]);
			}
		}
		if(ans < 0) cout << -1 << endl;
		else cout << ans << endl;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值