题目描述略为坑爹,其中n取值应该为0<=n<=1000,0<=ai,di<=2500,否则在POJ上无法AC。另外1<=ti<=20这个条件可以忽略。同时ti<=di-ai<2*ti表明了一个工作只能做一次。其实题中也并没有表述工作可以在它对应的时间内重复做。。。
定义状态dp[i]表示在i时刻时,还需要工作的最少时间。由条件可以知道,每一个工作所能被做的时间段为ai~di-ti,这样便可以根据输入把每个时刻可以做的工作构成一个集合。所以对于时刻i,有dp[i] = min(dp[i],dp[i+t[k]]+t[k]);表示在i时刻做了第k个工作。如果i时刻没有工作可做,则dp[i] = dp[i+1]。边界条件为dp[maxi]=0;既所以工作的最大deadline是不可能再工作的。然后进行记忆化搜索。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int SIZE = 1280;
int cas,n,maxi;
int t[SIZE],a[SIZE],d[SIZE];
int dp[SIZE<<1];
bool vis[SIZE<<1];
vector <int> v[SIZE<<1];
int DP(int tim)
{
if(vis[tim])
return dp[tim];
if(tim >= maxi)
{
dp[maxi] = 0;
return 0;
}
if(v[tim].size() == 0)
dp[tim] = DP(tim+1);
else
{
for(int i=0; i<(int)v[tim].size(); i++)
{
int to = v[tim][i];
dp[tim] = min(dp[tim],DP(tim+t[to])+t[to]);
}
}
vis[tim] = true;
return dp[tim];
}
int main()
{
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
for(int i=0; i<256; i++)
v[i].clear();
maxi = 0;
for(int i=1; i<=n; i++)
{
scanf("%d%d%d",&t[i],&a[i],&d[i]);
for(int k=a[i]; k<=d[i]-t[i]; k++)
v[k].push_back(i);
if(d[i] > maxi)
maxi = d[i];
}
for(int i=0; i<SIZE; i++)
dp[i] = 0xfffffff;
for(int i=maxi; i<SIZE; i++)
dp[i] = 0;
memset(vis,0,sizeof(vis));
DP(0);
printf("%d\n",dp[0]);
}
return 0;
}