PAT顶级 1002 Business (35分)(0/1背包)

思路:

1.每份工作只有做和不做,问最大利润,自然就能想到0/1背包问题;
2.设dp[i][j]dp[i][j]表示用jj天的时间,在前ii个工程中所能获得的最大利润,设wk[i]wk[i]为第ii个工作,wk[i].prowk[i].prowk[i].costwk[i].costwk[i].ddlwk[i].ddl分别代表利润、花费的时间和截止日期,则我们有
dp[i][j]={dp[i1][j]j<wk[i].costmax(dp[i1][j],dp[i1][jwk[i].cost]+wk[i].pro)wk[i].costjwk[i].ddlmax(dp[i1][j],dp[i][j1])j>wk[i].ddldp[i][j]= egin{cases} dp[i-1][j]&j<wk[i].cost\ max(dp[i-1][j],dp[i-1][j-wk[i].cost]+wk[i].pro)& wk[i].cost leq j leq wk[i].ddl\ max(dp[i-1][j],dp[i][j-1])& j>wk[i].ddl end{cases}
和普通背包不同的就是在日期超过ddlddl时我们无法通过完成第ii份工作来达到第jj天,因此有第三行的递推式;
3.相同的几个工作,我们肯定需要先完成截止日期近的工作,因此需要对数组内容按截止日期进行排序;

代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int maxn=52;
int n,lmt=0;
vector<int> dp[maxn];
struct work{int pro,cost,ddl;}wk[maxn];
void solve(){
	for(int i=0;i<=n;i++) dp[i].resize(lmt+1);
	sort(wk+1,wk+n+1,[](const work& w1,const work& w2){return w1.ddl<w2.ddl;});
	for(int i=1;i<=n;i++){
		for(int j=1;j<=lmt;j++){
			if(j>=wk[i].cost&&j<=wk[i].ddl)
				dp[i][j]=max(dp[i-1][j],dp[i-1][j-wk[i].cost]+wk[i].pro);
			else if(j<wk[i].cost) dp[i][j]=dp[i-1][j];
			else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
		}
	}
	cout<<dp[n][lmt];
}
int main(){
//	freopen("Sakura.txt","r",stdin);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>wk[i].pro>>wk[i].cost>>wk[i].ddl;
		lmt=max(lmt,wk[i].ddl);
	}
	solve();
	return 0;
}
原文地址:https://www.cnblogs.com/yuhan-blog/p/12308741.html