题意:有 n n n门课,给出课的名称,ddl,所需时间,然后要让超出ddl的时间数之和最小。
题解:状压dp
用二进制枚举所有状态,再遍历当前状态的所有子状态(1),倒推过去取最大就可以。见代码注释。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<cstring>
#include<stack>
#include<algorithm>
const int maxn = 1e6 + 5;
const int inf = 2147483647;
using namespace std;
int t, n;
struct node {
string s;
int ddl, need;
}pro[22];
struct nnode {
int time, score, pre, now;
}dp[1 << 15];
void printans(int x) {
if (dp[x].pre) printans(dp[x].pre);
cout << pro[dp[x].now].s << endl;
}
int main() {
scanf("%d", &t);
while (t--) {
memset(dp, 0, sizeof(dp));
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
cin >> pro[i].s >> pro[i].ddl >> pro[i].need;
}
for (int i = 1; i <= (1 << n) - 1; i++) { //枚举每一个状态(没有一个完成到所有的都完成)
dp[i].score = inf;
for (int j = n ; j >= 0; j--) { //枚举只有一门课完成的情况(从第1门到第n门)
int temp = 1 << (j - 1);
if (i & temp) { //这个状态有这门课
int past = i - temp; //没有选这门课的状态
int reduce = dp[past].time + pro[j].need - pro[j].ddl;
if (reduce < 0) reduce = 0;
if (dp[past].score + reduce < dp[i].score) {
dp[i].score = dp[past].score + reduce;
dp[i].now = j;
dp[i].pre = past;
dp[i].time = dp[past].time + pro[j].need;
}
}
}
}
cout << dp[(1 << n) - 1].score << endl;
printans((1 << n) - 1);
}
return 0;
}