作业的先后顺序问题、 一看最多只有15次作业。 就可以用二进制状态压缩。
对于一个状态 111 这三个作业。 可以来自 110 + 1 也可以来自 101 | (1<<2) 也可以来自 011 | (1<<3) 取一个花费时间最少的就好。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define MAXN 10+10
#define INF (1<<30)
#define mod 123456789
struct Home{
string s;
int en;
int need;
};
struct score{
int time;
int sco;
int last;
int pos;
};
int main (){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
Home h[MAXN];
for(int i = 0; i < n; i++){
cin >> h[i].s;
scanf("%d%d",&h[i].en,&h[i].need);
}
int all = (1<<n);
score d[1<<15];
memset(d,0,sizeof(d));
for(int i = 1; i < all; i++){
d[i].sco = INF;
for(int j = n-1; j >= 0; j--){
if(i&(1<<j)){
int last = i-(1<<j);
int tt = d[last].time+h[j].need-h[j].en;
if(tt<0) // 说明 提前结束
tt = 0;
if(tt+d[last].sco < d[i].sco){
d[i].sco = tt+d[last].sco;
d[i].last = last;
d[i].time = d[last].time+h[j].need;
d[i].pos = j;
// printf("%d %d %d %d %d\n",i,d[i].sco,d[i].last,d[i].time,d[i].pos);
}
}
}
}
stack <int> q;
int end_ = d[all-1].last;
q.push(d[all-1].pos);
while(true){
if(end_ == 0)
break;
q.push(d[end_].pos);
end_ = d[end_].last;
}
printf("%d\n",d[(1<<n)-1].sco);
while(!q.empty()){
int tt = q.top();
q.pop();
cout << h[tt].s << endl;
}
}
return 0;
}