传送门
题意
给出n个任务的结束时间和持续时间,完成一个任务扣掉的分数为完成时间-结束时间,问最少扣掉多少分数
分析
观察到n为15,那么
我们将任务完成情况保存为状态,dp[i]表示到达i状态所扣的最少分数。
dp[i]由哪些状态到达?
枚举任务,对于第k个任务,在j中对于i中的任务只有k未完成,$$dp[i]=min(dp[j]+score)$$
对于路径建立一个pre数组
-END-
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define F(i,a,b) for(int i=a;i<=b;++i)
#define R(i,a,b) for(int i=a;i<b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
const int inf=0x3f3f3f3f;
char s[20][111];
int t,n,dead[20],cost[20],pre[1<<17],dp[1<<17],tim[1<<17];
void output(int x)
{
if(x==0) return ;
output(x-(1<<pre[x]));
printf("%s
",s[pre[x]]);
}
int main()
{
for(scanf("%d",&t);t--;)
{
scanf("%d",&n);
R(i,0,n)
{
scanf("%s%d%d",&s[i],dead+i,cost+i);
}
for(int i=1;i<(1<<n);++i) {dp[i]=inf;}
for(int i=1;i<(1<<n);++i)for(int k=n-1;k>=0;--k)
{
int j=i-(1<<k);
if((1<<k)&i)
{
int score=max(tim[j]+cost[k]-dead[k],0);
if(dp[i]>dp[j]+score)
{
dp[i]=dp[j]+score;
tim[i]=tim[j]+cost[k];
pre[i]=k;
}
}
//printf("pre[%d]=%d
",i,pre[i]);
//printf("tim[%d]=%d dp[%d]=%d
",i,tim[i],i,dp[i]);
}
//for(int i=1;i<(1<<n);++i) printf("pre[%d]=%d
",i,pre[i]);
printf("%d
",dp[(1<<n)-1]);
output((1<<n)-1);
}
return 0;
}