题目大意是小明有很多功课要去做,都要做完,每门课有一个截止时间和做它需要的时间。
注意到数据量是15,这很明显告诉我们可以枚举用二进制
对,一开始我还真的没想出来状态是什么
看到数据量后,就以二进制为状态
比如7就表示第一门第二门第三门功课做完需要最小的时间
下面贴代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
struct po
{
char name[101];
int d,l;
};
po a[50];
struct node
{
int pre,now,v,time;
};
node dp[(1<<16)];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
getchar();
for(int i=0;i<n;i++){
scanf("%s %d%d%*c",a[i].name,&a[i].d,&a[i].l);
//printf("%s %d %d\n",a[i].name,a[i].d,a[i].l);
}
for(int i = 1;i<(1<<n);i++){ //枚举二进制状态
dp[i].v = inf;
for(int j=n-1;j>=0;j--){
if((i>>j)&1){
int past = i-(1<<j);
int tt = dp[past].time + a[j].l - a[j].d;
if(tt<0) tt=0;
if(dp[past].v + tt < dp[i].v){
dp[i].v = dp[past].v + tt;
dp[i].time = dp[past].time + a[j].l;
dp[i].now = j;
dp[i].pre = past;
}
}
}
}
printf("%d\n",dp[(1<<n)-1].v);
int tmp = (1<<n)-1; // 结果要倒过来输出
stack<int> S;
while(tmp){
S.push(dp[tmp].now);
tmp = dp[tmp].pre;
}
while(!S.empty()){
int i = S.top();S.pop();
printf("%s\n",a[i].name);
}
}
return 0;
}
学dp的路还很长,坚持才能逐渐掌握。
毕竟这世界套路太深。