思路:
1.每份工作只有做和不做,问最大利润,自然就能想到0/1背包问题;
2.设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示用
j
j
j天的时间,在前
i
i
i个工程中所能获得的最大利润,设
w
k
[
i
]
wk[i]
wk[i]为第
i
i
i个工作,
w
k
[
i
]
.
p
r
o
wk[i].pro
wk[i].pro、
w
k
[
i
]
.
c
o
s
t
wk[i].cost
wk[i].cost和
w
k
[
i
]
.
d
d
l
wk[i].ddl
wk[i].ddl分别代表利润、花费的时间和截止日期,则我们有
d
p
[
i
]
[
j
]
=
{
d
p
[
i
−
1
]
[
j
]
j
<
w
k
[
i
]
.
c
o
s
t
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
w
k
[
i
]
.
c
o
s
t
]
+
w
k
[
i
]
.
p
r
o
)
w
k
[
i
]
.
c
o
s
t
≤
j
≤
w
k
[
i
]
.
d
d
l
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
j
>
w
k
[
i
]
.
d
d
l
dp[i][j]= \begin{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}
dp[i][j]=⎩⎪⎨⎪⎧dp[i−1][j]max(dp[i−1][j],dp[i−1][j−wk[i].cost]+wk[i].pro)max(dp[i−1][j],dp[i][j−1])j<wk[i].costwk[i].cost≤j≤wk[i].ddlj>wk[i].ddl
和普通背包不同的就是在日期超过
d
d
l
ddl
ddl时我们无法通过完成第
i
i
i份工作来达到第
j
j
j天,因此有第三行的递推式;
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;
}