题意:
给出N个物品,每个物品拿取需要ti时间,di之间之后这个物品就不能拿了,物品的价值为pi,问怎样拿能够拿最多价值的物品,问这些物品拿取的顺序。
dp[i][j]表示尝试取到第i个物品以时刻j为结束时间的最大价值
AC代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n;
int dp[105][2005];
int pos[105][2005];//pos[i][j]表示在尝试取到第i个物品时以j时刻为结束时间的状态时 是否选取了数组编号为a[i].k的物品
int b[105];
int ans;//最大价值,物品个数
struct node
{
int c,e,v,k;//抢救需要花费的时间,最迟抢救时间,价值 ,第几个物品
}a[105];
int cmp(node x,node y)
{
return x.e<y.e;//越紧急的排前面
}
void print(int i,int j,int num)//逆序
{
if(i==0)//n个物品都遍历完了
{
printf("%d\n",num);//就输出被选取的个数
return;//开始回溯输出依次选取的物品
}
if(pos[i][j]==0)//该状态不存在(这个物品没有抢救)
{
print(i-1,j,num);//就找上一个物品,时间不变 (没有花费时间),抢救物品的个数也不变
}
else
{
print(i-1,j-a[i].c,num+1);//该状态存在,就找上一个物品,减去抢救当前物品花费的时间,抢救物品的个数加1
printf("%d ",a[i].k);//递归回溯,输出抢救物品的序号
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
scanf("%d %d %d",&a[i].c,&a[i].e,&a[i].v),a[i].k=i;
sort(a+1,a+n+1,cmp);
memset(dp,0,sizeof(dp));
memset(pos,0,sizeof(pos));
for(int i=1;i<=n;i++)
{
for(int j=0;j<=2000;j++)
{
dp[i][j]=dp[i-1][j];//假设不抢救该物品
if(j>=a[i].c&&j<a[i].e)//有时间并且物品还没毁掉
{
if(dp[i][j]<dp[i-1][j-a[i].c]+a[i].v)//如果 "不抢救该物品"没有"抢救该物品"获得的最大价值大
{
dp[i][j]=dp[i-1][j-a[i].c]+a[i].v;//就更新当前状态,抢救该物品,否则就默认为不抢救(之前赋过值了)
pos[i][j]=1;//标记说明该状态时抢救了该物品
}
}
}
}
ans=-1;
int time;//选取找到最大值时的时刻
for(int i=0;i<=2000;i++)
if(dp[n][i]>ans) ans=dp[n][i],time=i;//找出最大价值,这里时间没有明确限制,就比到题目给定的时间范围为止
printf("%d\n",ans);
print(n,time,0);//n个物品,time时长,初始抢救了0个物品,从这里开始调用函数根据最后一个时刻找出的物品逆推
printf("\n");
}
return 0;
}