题意:多样例测试。给你n个作业,每个作业有名字、截止时间以及写作业花费的时间,求出写作业的顺序使扣分最少(超过规定截止时间就扣一分)。将作业名字按先后输出,如果多个作业一起完成的,按字典序排序。
注:输入时便是字典序输入
思路:状态压缩dp[1<<n]二进制中某一位为1便是已经完成的作业。为保证输出字典序排序,从后往前遍历。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<stack>
using namespace std;
const int N=16,M=1<<N,INF=0x3f3f3f3f;
struct Node{
char name[110];
int end;
int cost;
} node[N];
struct DP{
int pre;//存储上一个状态
int now;//当前的作业的编号
int time;//当前完成的作业所消耗的总时间
int score;//当前完成的作业所扣的分
} dp[M];
int n;
int main()
{
int t;
cin>>t;
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s%d%d",node[i].name,&node[i].end,&node[i].cost);
memset(dp,0,sizeof dp);
for(int i=1;i<(1<<n);i++)
{
dp[i].score=INF;
for(int j=n-1;j>=0;j--)//从小到大遍历,保证最后字典序输出
{
int s=1<<j;
if(s&i)
{
int past=i-s;//上一个状态
int st=dp[past].time+node[j].cost-node[j].end;//当前扣分情况
if(st<0)//说明当前完成的作业可以在截止时间完成,则不用扣分
st=0;
if(st+dp[past].score<dp[i].score)//找到更小的扣分情况,更新
{
dp[i].score=dp[past].score+st;
dp[i].pre=past;
dp[i].time=dp[past].time+node[j].cost;
dp[i].now=j;
}
}
}
}
stack<int>ss;
printf("%d\n",dp[(1<<n)-1].score);
int tmp=(1<<n)-1;
while(tmp)
{
ss.push(dp[tmp].now);
tmp=dp[tmp].pre;
}
while(ss.size())
{
int t=ss.top();
printf("%s\n",node[t].name);
ss.pop();
}
}
return 0;
}