input:
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3
output:
2
Computer
Math
English
3
Computer
English
Math
题目大意:
n个作业,每个有也有截止日期和需要花费的天数。如果超过截止时间一天,分数-1,求如何安排作业的先后,让
扣的分数最少。
分析:
状态dp。比较巧妙,使用11111的数串表示第1,2,3,5,6的作业都完成了。所以对一个i状态的方案,枚举作
业j,求出完成作业j需要扣掉的分数。详细看代码。
code:
#define frp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f;
const ll inf = 0x7fffff;
const int maxn = 1<<15;
const int MAXN = 10000;
int dp[maxn],pre[maxn],T[maxn],deadline[50],cost[50];
string sub[50];
int t;
void print(int x){
if(!x)return;
print(x^(1<<pre[x]));
cout<<sub[pre[x]]<<endl;
}
void solve() {
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>sub[i]>>deadline[i]>>cost[i];
}
int sum=1<<n;
for(int i=1;i<sum;i++){
dp[i]=inf;
for(int j=n-1;j>=0;j--){
int tmp=1<<j;
//如果i方案里没有完成j作业,则continue;
if(!(i&tmp))continue;
tmp=i^tmp;
//完成j作业所要扣的分数T[]数组是完成tmp的方案的天数
int minus=T[tmp]+cost[j]-deadline[j];
if(minus<0)minus=0;
if(dp[tmp]+minus<dp[i]){
dp[i]=dp[tmp]+minus;
T[i]=T[tmp]+cost[j];
pre[i]=j;
}
}
}
cout<<dp[sum-1]<<endl;
print(sum-1);
memset(pre,0, sizeof(pre));
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
#ifdef frp
freopen("D:\\coding\\c_coding\\in.txt", "r", stdin);
// freopen("D:\\coding\\c_coding\\out.txt", "w", stdout);
#endif
solve();
return 0;
}