状态压缩。
注意输出要依照字典序。所以实际在写的时候要注意方向,
若果是每次枚举可以加的课程,那么此时从0到n,
否则每次枚举可以删掉的课程,那么此时从n到0进行枚举。
#include<cstdio>
#include<iostream>
#include<string>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
struct data
{
string name;
int d,c;
} d[20];
struct DP
{
int pre;
int time;
int cost;
int now;
}dp[1<<20];
void show(DP a)
{
if(a.pre==-1)
return ;
show(dp[a.pre]);
cout<<d[a.now].name<<endl;
}
bool cmp(data a,data b)
{
return a.name<b.name;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
for(int i=0; i<n; i++)
{
cin>>d[i].name>>d[i].d>>d[i].c;
}
// sort(d,d+n,cmp);
memset(dp,0x3f,sizeof dp);
dp[0].pre=-1;
dp[0].cost=dp[0].time=0;
//
// for(int i=1; i<1<<n; i++)
// {
// dp[i].cost=0x3f3f3f3f;
// for(int j=0; j<n; j++)
// {
// if(i&(1<<j))
// {
// int tmp=(dp[i-(1<<j)].time+d[j].c)-d[j].d;
// if(tmp<0)
// tmp=0;
//
// if(dp[i-(1<<j)].cost+tmp<dp[i].cost)
// {
// printf("j:%d\n",j);
// dp[i].cost=dp[i-(1<<j)].cost+tmp;
// dp[i].time=dp[i-(1<<j)].time+d[j].c;
// dp[i].pre=i-(1<<j);
// dp[i].now=j;
//
// }
//
// }
//
// }
// }
for(int i=0;i<(1<<n);i++)
{
for(int j=0;j<n;j++)
{
if(i&(1<<j))
continue;
int tmp=0;
tmp=dp[i].time+d[j].c-d[j].d;
if(tmp<0)
tmp=0;
if(dp[i+(1<<j)].cost>dp[i].cost+tmp)
{
dp[i+(1<<j)].cost=dp[i].cost+tmp;
dp[i+(1<<j)].time=dp[i].time+d[j].c;
dp[i+(1<<j)].now=j;
dp[i+(1<<j)].pre=i;
}
}
}
printf("%d\n",dp[(1<<n)-1].cost);
show(dp[(1<<n)-1]);
}
return 0;
}