// [9/11/2014 Sjm]
/*
hdu 1074 (状态压缩)
dp[i]: 表示在 i 状态时的最优解
(i状态: i数值用二进制表示, 若二进制数第 n 位为1,代表第 n 个课程已被计算)
思路: 详见代码注释(举几个简单例子模拟一下,可以明白的更清楚一些)
*/
1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 #include <cstring>
5 #include <string>
6 using namespace std;
7 const int MAX = 1 << 16, MAX_N = 20, INF = 0x3f3f3f3f;
8 int N;
9 bool Vis[MAX];
10
11 struct myNode {
12 int nowTime; // 当前时间
13 int pre; // 前一个状态
14 int minReduce; // 被扣掉的分数
15 } dp[MAX];
16
17 struct mySubject {
18 string name; // 课程名
19 int deadline; // 最后期限
20 int cost; // 所需要花费的时间
21 } subject[MAX_N];
22
23 int getPos(int x) {
24 int pos = 0;
25 while (x) {
26 ++pos;
27 x >>= 1;
28 }
29 return (pos - 1);
30 }
31
32 void Output(int State) {
33 if (0 == State) return;
34 int nowSub = (State^dp[State].pre); // 为了获取当前课程是第几个 ==> getPos(nowSub)
35 Output(dp[State].pre);
36 cout << subject[getPos(nowSub)].name << endl;
37 }
38
39 void Solve() {
40 memset(Vis, false, sizeof(Vis));
41 for (int i = 0; i < N; ++i) dp[i].minReduce = INF;
42 dp[0].nowTime = 0;
43 dp[0].pre = -1;
44 dp[0].minReduce = 0;
45 Vis[0] = true;
46 int finalState = (1<<N) - 1;
47 for (int state = 0; state < finalState; ++state) { // 遍历所有状态
48 for (int subPos = 0; subPos < N; ++subPos) { // 在当前状态下加入subPos课程
49 int sub = (1 << subPos);
50 if (0 == (sub&state)) { // 判断当前subPos课程是否已经计算过,若没有则进行计算,否则需寻找其他课程
51 int nowState = state | sub; // 计算过subPos课程后,所到达的新的状态
52 int finish_nowState_Time = dp[state].nowTime + subject[subPos].cost;
53 // 完成subPos课程后,整个状态所到达的时间
54 int nowStateReduce = finish_nowState_Time - subject[subPos].deadline;
55 if (nowStateReduce < 0) nowStateReduce = 0;
56 // 仅仅因为subPos课程所需要被扣掉的分数
57 nowStateReduce = dp[state].minReduce + nowStateReduce;
58 // 完成subPos课程后,整个状态需要被扣掉的分数
59 if (Vis[nowState]) {
60 // 若新的状态之前到达过,则与完成subPos课程到达此状态时,所被扣掉的分数进行比较
61 // 若之前到达该状态时,所被扣掉的分数 > 完成subPos课程到达此状态时,所被扣掉的分数
62 // 则对该状态进行更新
63 if (dp[nowState].minReduce > nowStateReduce) {
64 dp[nowState].minReduce = nowStateReduce;
65 dp[nowState].pre = state;
66 dp[nowState].nowTime = finish_nowState_Time;
67 }
68 }
69 else {
70 // 若新的状态之前没有到达过,直接赋值更新
71 Vis[nowState] = true;
72 dp[nowState].minReduce = nowStateReduce;
73 dp[nowState].pre = state;
74 dp[nowState].nowTime = finish_nowState_Time;
75 }
76 }
77 }
78 }
79 printf("%d
", dp[finalState].minReduce);
80 Output(finalState); // 递归输出所选择课程的顺序
81 }
82
83 int main() {
84 //freopen("input.txt", "r", stdin);
85 //freopen("output.txt", "w", stdout);
86 int Case;
87 scanf("%d", &Case);
88 while (Case--) {
89 scanf("%d", &N);
90 for (int i = 0; i < N; ++i) {
91 cin >> subject[i].name;
92 scanf("%d %d", &subject[i].deadline, &subject[i].cost);
93 }
94 Solve();
95 }
96 return 0;
97 }