题目链接 HDU 1074
大概题意
现在有N项作业要做,每个作业有一个最晚的完成期限天和完成需要的天数,如果超过这个期限天数,超过一天扣掉一分,问你完成这N项作业之后,扣掉的最小的分数是多少。
解题思路
刚开始看这个题还以为是个贪心,然而感觉怎么贪都不太对… …最后查了一下题解是个状压dp,因为N很小,所以枚举每个状态,每个状态取最小值,到最后每个作业都写的时候,最小的扣分数就是答案了
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
using namespace std;
int inf=0x3f3f3f3f;
struct node
{
char s[105];
int pre,time,score,now,dead,cost;
};
node e[1<<16];
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s %d %d",e[i].s,&e[i].dead,&e[i].cost);
int alls=1<<n;
for(int i=1;i<alls;i++)
{
e[i].score=inf;
for(int j=n-1;j>=0;j--)
{
if((1<<j)&i)
{
int past=i-(1<<j);//没有写第j个作业的时候,也就是上一个状态
int alltime=e[past].time+e[j].cost-e[j].dead;//写这个作业扣的分数
if(alltime<0)
alltime=0;
if(e[past].score+alltime<e[i].score)//更新最小值
{
e[i].score=e[past].score+alltime;
e[i].now=j;
e[i].pre=past;
e[i].time=e[past].time+e[j].cost;
}
}
}
}
printf("%d\n",e[alls-1].score);
int k=alls-1;
stack<int>ss;
while(k)
{
ss.push(e[k].now);
//printf("%s\n",e[e[k].now].s);
k=e[k].pre;
}
while(!ss.empty())//字典序最小输出
{
printf("%s\n",e[ss.top()].s);
ss.pop();
}
}
return 0;
}