思路:
- 不是普通01背包吗?有两个问题:
- 手推样例就可以发现,如果不对区间 sort,则裸的01背包无法得出正确结果。
- 即使根据右端点排序后进行01背包,可能是对的,但是会 TLE。
- 那么现在为了降低时间复杂度,将对每个点时间的 dp 变为对每个物品(区间)的 dp。
- 又出现一个问题:dp[i] 应该代表 “ 必须使用 i 区间 ”,还是 “ 前 i 个区间可以得到的最优解 ” ?
答案:都可以。
总结:
- 关于时间区间的 dp,必须要(按右端点)sort 。
- 因为有了 sort,要注意 pre[maxn] 数组的使用。
- 对全部时间 dp TLE 时,可以变成对每段的 dp。
- 用不用 MAX,取决于上文的第二个问题。
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 1e6 + 5;
const int maxm = 1e3 + 5;
int N,M,REST;
int dp[maxn];
struct NODE{
int l , r , w;
friend bool operator < (NODE a , NODE b)
{
return a.r < b.r;
}
}node[maxm];
void ADDNODE(int i,int l,int r,int w){
node[i].l = l;
node[i].r = r;
node[i].w = w;
return;
}
int SOLVE(){
sort(node , node+M);
memset(dp , 0 , sizeof(dp));
for(int i=0;i<M;i++)
for(int j=N;j>=node[i].r;j--)
if(node[i].l >= REST)
dp[j] = max(dp[j] , dp[node[i].l - REST] + node[i].w);
else
dp[j] = max(dp[j] , node[i].w);
return dp[N];
}
int main(){
cin>>N>>M>>REST;
for(int i=0;i<M;i++){
int l,r,w;
scanf("%d%d%d" , &l , &r , &w);
ADDNODE(i,l,r,w);
}
cout<<SOLVE()<<endl;
return 0;
}
- dp[i] 代表 “ 前 i 个区间可以得到的最优解 ” :63ms 744kB
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e3 + 5;
int N,M,R;
int pre[maxn];
int dp[maxn] ;
struct NODE{
int l,r,w;
friend bool operator < (NODE a , NODE b)
{
return a.r < b.r;
}
}node[maxn];
void FINDPRE(){
for(int i=1;i<=M;i++){
int k = i-1;
while(k && node[k].r + R > node[i].l)
k--;
pre[i] = k;
}
return ;
}
int SOLVE(){
memset(dp , 0 , sizeof(dp));
for(int i=1;i<=M;i++)
dp[i] = max(dp[i-1] , dp[pre[i]] + node[i].w);
return dp[M];
}
int main(){
cin>>N>>M>>R;
for(int i=1;i<=M;i++)
cin>>node[i].l>>node[i].r>>node[i].w;
sort(node + 1 , node + M + 1);
FINDPRE();
cout<<SOLVE()<<endl;
return 0;
}
- dp[i] 代表 “ 必须使用 i 区间 ” :63ms 748KB
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e3 + 5;
int N,M,R;
int pre[maxn];
int dp[maxn] ;
struct NODE{
int l,r,w;
friend bool operator < (NODE a , NODE b)
{
return a.r < b.r;
}
}node[maxn];
void FINDPRE(){
for(int i=1;i<=M;i++){
int k = i-1;
while(k && node[k].r + R > node[i].l)
k--;
pre[i] = k;
}
return ;
}
int SOLVE(){
memset(dp , 0 , sizeof(dp));
int MAX = 0;
for(int i=1;i<=M;i++){
if(pre[i])
for(int j=1;j<=pre[i];j++)
dp[i] = max(dp[i] , dp[j] + node[i].w);
else
dp[i] = node[i].w;
MAX = max(MAX , dp[i]);
}
return MAX;
}
int main(){
cin>>N>>M>>R;
for(int i=1;i<=M;i++)
cin>>node[i].l>>node[i].r>>node[i].w;
sort(node + 1 , node + M + 1);
FINDPRE();
cout<<SOLVE()<<endl;
return 0;
}