最多15个作业,如果全排列则共有15!种,但是这样会计算很多重复的值,用状压DP,遍历2^15,可以枚举所有作业的出现顺序,并且通过记录,可以进行递推。
初始状态是0,最后的状态是2^16-1(111111....)表示所有的作业都已经做过了。
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <string>
using namespace std;
#define maxn 65538
#define inf 999999
class node
{
public:
int dead,spen;
string s;
}que[22];
class nodee
{
public:
int pre,day,sum;
}dp[maxn];
int cmp[maxn],vis[maxn];
void init()
{
for(int i=0;i<16;i++)
cmp[1<<i]=i;
}
void drawBack(int n)
{
int a[20],top=0;
for(int i=n;i!=-1;i=dp[i].pre)
{
int pre=dp[i].pre;
if(pre==-1) break;
int tmp=i^dp[i].pre;
tmp=cmp[tmp];
a[top++]=tmp;
}
for(int i=top-1;i>=0;i--)
cout<<que[a[i]].s<<endl;
}
int main()
{
int n;
init();
int T;
cin>>T;
while(T--)
{
cin>>n;
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
cin>>que[i].s>>que[i].dead>>que[i].spen;
}
dp[0].pre=-1;
dp[0].day=0;
dp[0].sum=0;
int maxnum = 1<<n;
for(int i=0;i<maxnum;i++)
{
for(int j=0;j<n;j++)
{
int k=1<<j;
if((i&k)==0)
{
int neww=i|k;
int tmp=que[j].spen+dp[i].day;
int sum=dp[i].sum;
if(tmp>que[j].dead)
sum+=tmp-que[j].dead;
if(vis[neww])
{
if(sum<dp[neww].sum)
{
dp[neww].sum=sum;dp[neww].pre=i;dp[neww].day=tmp;
}
else if(sum==dp[neww].sum)
{
if(i<dp[neww].pre) dp[neww].pre=i;
}
}
else
{
vis[neww]=1;
dp[neww].sum=sum;dp[neww].pre=i;dp[neww].day=tmp;
}
}
}
}
cout<<dp[maxnum-1].sum<<endl;
drawBack(maxnum-1);
}
return 0;
}