大概题意是有n门作业,对于每一门作业,他做完需要C天,但是作业要在D天之前交,玩一天扣一分,问如何排列作业的顺序使得扣得分最少...
状压DP,暑假的时候做过这个题目,当时没做出来找学长帮忙了...现在做起来依旧很吃力,还找出来以前的程序对照了一下...。
思路就是,当一个状态值是x的时候,他有a个1,那么x的最优情况是从有a-1个1并且加上一个1能得到x的所有状压值里面的最优解...比如完成之后是110的,他可能由010和100得到...然后只需要记录一下路径就好了....
#include<cstdio>
#include<cstring>
#define INF 0x3fffffff
struct node
{
char name[110];
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=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 i,j,n,t;
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++)
{
if(((1<<j)&i)!=0)
{
if(dp[i].t>getadd(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;
}