题目大意:
T组样例,N科作业,接下来N行,每行包括作业名称(字典序排列),截至时间,消耗时间,
每门作业,晚完成每分钟减一分,输出做少罚分与对应字典序小的做作业顺序
思路:
对于每门课建一个map给予编号t ,1<<t表示完成,由于输出时要输出科目顺序,所以需要记录最小值的前一门作业,时间和分数和当前科目
就是给dp数组建成结构体,过程比较简单
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
#include<stack>
#include<map>
using namespace std;
stack<int>S;
map<int,string>m;
int N,T,c[16],v[16];
struct AA
{
int fname,grade,time,n;
}dp[1<<17];
char ch[100];
int main()
{
int i,j,k,a,b;
cin>>T;
while(T--)
{
memset(dp,0,sizeof(dp));
scanf("%d",&N);
for(i=0;i<N;i++)
{
scanf("%s%d%d",ch,&c[i],&v[i]);
m[i]=ch;
}
for(i=1;i<(1<<N);i++)
{
dp[i].grade=0x3f3f3f3f;
for(j=N-1;j>=0;j--)//从后到前更新,满足字典序
{
if(i&1<<j)//i的第j-1门课做了
{
int z=i-(1<<j);//除去第j-1门课
if(dp[i].grade>dp[z].grade+max(0,dp[z].time+v[j]-c[j]))//每门课最少扣0分,找最优解
{
dp[i].grade=dp[z].grade+max(dp[z].time+v[j]-c[j],0);
dp[i].fname=z;//前一个状态
dp[i].n=j;//刚添加的课程
dp[i].time=dp[z].time+v[j];
}
}
}
}
int l=(1<<N)-1;
cout<<dp[l].grade<<endl;
while(l)
{
S.push(dp[l].n);//从末状态,按最佳路径推回到初状态
l=dp[l].fname;
}
while(!S.empty())
{
cout<<m[S.top()]<<endl;
S.pop();
}
}
}