题目大意:有N个功课,给出每个功课的截止时间和做完这个功课所需要的时间
如果到了截止时间,该功课还没有做完,就要付出 做完该功课的时间-该功课的截止时间 的代价
问做完所有功课所需花费的最小代价,和做功课的顺序

解题思路:因为只有15门功课,所以可以使用状态压缩
预处理出每种状态下完成功课的时间
用dp[i]表示做完i状态下的功课所需要付出的最小代价
假设i状态下,j功课还没有做
dp[i | (1 << j)] = min(dp[i | (1 << j)], dp[i] + Time[i | (1 << j)] - deadline[j])
其中Time指的是完成该状态下的功课所需要花费的时间,deadline表示截止时间

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <queue>
using namespace std;
const int N = (1 << 15) + 10;
const int INF = (1 << 30);

struct Course{
    char name[110];
    int deadline, last;
}C[20];

int n; 
int dp[N], path[N];
int Time[N], pow2[30];

void init() {
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%s%d%d", C[i].name, &C[i].deadline, &C[i].last);

    for (int i = 0; i < (1 << n); i++) {
        Time[i] = 0;
        dp[i] = INF;
        for (int j = 0; j < n; j++)
            if (i & (1 << j)) Time[i] += C[j].last;
    }
}

void out(int s) {
    if (s == 0) 
        return ;
    out(path[s]);
    int t = s - path[s];
    for (int i = 0; i < n; i++)
        if (pow2[i] == t) {
            printf("%s\n", C[i].name);
            return ;
        }
}

void solve() {
    queue<int> Q;
    for (int i = 0; i < n; i++) {
        Q.push(1 << i);
        int t = C[i].last;
        int Sum = (C[i].last > C[i].deadline ? C[i].last - C[i].deadline : 0);

        dp[1 << i] = Sum;
        path[1 << i] = 0;
    }

    while (!Q.empty()) {
        int s = Q.front(); Q.pop();

        for (int i = 0; i < n; i++) {
            if (s & (1 << i)) continue;
            else {
                int t = Time[s | (1 << i)];
                int Sum = (t > C[i].deadline ? t - C[i].deadline : 0);

                if (dp[s | (1 << i)] > dp[s] + Sum) {
                    dp[s | (1 << i)] = dp[s] + Sum;
                    path[s | (1 << i)] = s;
                    Q.push(s | (1 << i));
                }
            }

        }
    }
    printf("%d\n", dp[(1 << n) - 1]);
    out((1 << n) - 1);
}

void start() {
    pow2[0] = 1;
    for (int i = 1 ; i < 17; i++)
        pow2[i] = pow2[i - 1] * 2;
}

int main() {
    start();
    int test;
    scanf("%d", &test);
    while (test--) {
        init();
        solve();
    }
    return 0;
}