设
d
p
(
i
)
dp(i)
dp(i) 表示当前状态为 i 时,得到的最小扣分。
枚举最后的作业,来更新当前状态。
注意题目给出的是升序,故枚举最后的作业是逆序,最后的作业字典序尽可能的大。
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 16;
const int mod = 998244353;
//#define int long long
typedef long long ll;
int dp[1<<N],sum[1<<N],pre[1<<N];
struct Subject {
string name;
int d,c;
}sub[N];
signed main(){
IOS
#ifdef ddgo
freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
#endif
int tt; cin>>tt;
while(tt --) {
int n; cin>>n;
memset(dp,0x3f,sizeof(dp));
memset(pre,0,sizeof(pre));
memset(sum,0,sizeof(sum));
dp[0] = 0;
int si = (1 << n) - 1;
for(int i=0;i<n;i++) cin>>sub[i].name>>sub[i].d>>sub[i].c;
for(int i=1;i<=si;i++)
for(int j=n-1;j>=0;j--) {
int p = 1 << j;
if(!(i & p)) continue;
int w = max(0,sum[i ^ p] + sub[j].c - sub[j].d);
if(dp[i] > dp[i ^ p] + w) {
dp[i] = dp[i ^ p] + w;
sum[i] = sum[i ^ p] + sub[j].c;
pre[i] = j;
}
}
int j = pre[si];
cout<<dp[si]<<endl;
vector<string> ans;
while(si) {
ans.push_back(sub[j].name);
si = si ^ (1 << j);
j = pre[si];
}
reverse(ans.begin(),ans.end());
for(auto i : ans) cout<<i<<"\n";
}
return 0;
}