题意:老师给你布置一堆作业每个作业都规定了 上交的时间 你做每个作业所花费的时间也给出 如果到规定时间没上交做也晚交一天就要被老师扣一分 让你给出一个合理的做作业顺序 按这个顺序做完作业时被老师扣的分最少 如果答案有多个按字典序输出
题目链接:点击打开链接
//状态压缩dp
#include<stdio.h>
#include<string.h>
#define inf 0x3fffffff
struct node
{
char name[30];
int die;//老师规定的时间
int need;//需要的时间
}st[30];//存课程
struct stsort
{
int need;//完成当前状态包含的课程
int t;//当前状态已经被扣的分数
int qian;//用于记录当前状态最后完成的课程的编号
}dp[1<<16];
int limit;
void print(int x)//输出完成各个课程的顺序
{
int ans[30];
int l;
l=0;
while(x>0)
{
ans[l++]=dp[x].qian;
x=x-(1<<dp[x].qian);
}
l--;
while(l>=0)
{
printf("%s\n",st[ans[l]].name);
l--;
}
return ;
}
int getadd(int pos,int j)
{
int i,top,low,sum=0;
low=dp[pos-(1<<j)].need;
top=low+st[j].need;
pos=pos-(1<<j);
for(i=0;(1<<i)<limit;i++)
{
if(((1<<i)&pos)==0)
{
if(st[i].die<top)
sum+=st[i].die<low?(top-low):(top-st[i].die);
}
}
return dp[pos].t+sum;
}
int main()
{
int t,n,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
limit=1<<n;
for(i=0;i<limit;i++)
dp[i].t=inf;
dp[0].t=dp[0].need=0;
for(i=0;i<n;i++)
{
scanf("%s %d %d",st[i].name,&st[i].die,&st[i].need);
}
for(i=0;i<limit;i++)//遍历所有状态
{
for(j=0;(1<<j)<=i;j++)//遍历当前状态i 包含的科目
{
if(((1<<j)&i)!=0)//如果科目j包含在状态i中(j为i的子集)
{
if(dp[i].t>getadd(i,j))//最后加入课程j被扣的分 比当前状态i的扣分少 更新状态i 记录最后加入的是j
{
dp[i].t=getadd(i,j);
dp[i].need=dp[i-(1<<j)].need+st[j].need;
dp[i].qian=j;
}
else if(dp[i].t==getadd(i,j)&&strcmp(st[j].name,st[dp[i].qian].name)>0)//保证字典序 相同状态被扣分也相同时 字典序大的应该最后加入这个状态
{
dp[i].qian=j;
}
}
}
}
printf("%d\n",dp[limit-1].t);
print(limit-1);
}
return 0;
}