题意:
给你n门课的名字和完成这门课所需要的时间和这门课规定完成的时间,每超过规定的时间一分钟就多扣一分,问题是按怎样的顺序的去完成这些课才能扣最少的分,输出所扣的最少的分和课表顺序。
思路:
状态过多,如果用搜索的话,n最大为15,会超时。因此想到用状态压缩动态规划。状态压缩就是用位数为n二进制来表示n门课的选择情况,1表示选了,0表示还没选,再用动态规划来找出课被选完时扣掉的最少的分。用path数组来记录课表选择的顺序。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#define LL long long
#define MAX 1000005
#define inf 99999999
#define mod 1000000007
using namespace std;
struct node
{
int die;
int use;
char name[105];
};
node a[20];
int path[100005],time[100005],dp[100005];
char b[20][105];
int main()
{
int t,n,m,i,j,num,s,c;
while(scanf("%d",&t)!=EOF)
{
while(t--)
{
scanf("%d",&n);
memset(time,0,sizeof(time));
for(i=0;i<n;i++)
{
scanf(" %s",&a[i].name);
scanf("%d %d",&a[i].die,&a[i].use);
}
m=1<<n;
for(i=1;i<m;i++)
{
dp[i]=inf;
for(j=n-1;j>=0;j--)
{
num=1<<j;
if(!(i&num))
continue;
s=time[i-num]+a[j].use-a[j].die;
if(s<0)
s=0;
if(dp[i]>dp[i-num]+s)
{
dp[i]=dp[i-num]+s;
time[i]=time[i-num]+a[j].use;
path[i]=j;
}
}
}
printf("%d\n",dp[m-1]);
m=m-1;
c=0;
while(m!=0)
{
strcpy(b[c],a[path[m]].name);
c++;
m-=1<<path[m];
}
for(i=c-1;i>=0;i--)
printf("%s\n",b[i]);
}
}
return 0;
}