题目大意:
给出完成n门功课的所需要的时间和n门功课上交时间的deadline。
如果比deadline 晚交一天就要扣一分。
安排出完成顺序使得扣分最少。
思路分析:
dp[s] 表示完成了s 状态下的功课所扣分的最优解。
对于每一个状态,我们转移的时候将每一门没有完成的功课加入其中,这样就保证了逐一完成。
需要注意的是字典序最小的问题,开始的时候对输入的字符串从小到大排序,每次都从小到大加入状态中。
这样就可以保证加入的状态字典序最小。
还要输出方案,所以ans数组里保存了上一个状态和当前状态加入的功课。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
#include <map>
#include <string>
#define maxn 1005
using namespace std;
int dp[1<<15];
int ans[1<<15][2];
int time[1<<15];
struct node
{
string str;
int dead,cost;
bool operator < (const node &cmp)const
{
return str<cmp.str;
}
}a[20];
void print(int s)
{
if(s==0)return;
print(ans[s][0]);
cout<<a[ans[s][1]].str<<endl;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i].str>>a[i].dead>>a[i].cost;
sort(a,a+n);
memset(dp,0x3f,sizeof dp);
memset(time,0,sizeof time);
memset(ans,0,sizeof ans);
dp[0]=0;
for(int s=0;s<(1<<n);s++)
{
for(int i=0;i<n;i++)
{
if((1<<i)&s)continue;
int c=max(0,time[s]+a[i].cost-a[i].dead);
if(dp[s]+c < dp[s|(1<<i)])
{
dp[s|(1<<i)]=dp[s]+c;
time[s|(1<<i)]=time[s]+a[i].cost;
ans[s|(1<<i)][0]=s;
ans[s|(1<<i)][1]=i;
}
}
}
cout<<dp[(1<<n)-1]<<endl;
print(ans[(1<<n)-1][0]);
cout<<a[ans[(1<<n)-1][1]].str<<endl;
}
return 0;
}