题意:有n门课,每门课有截止时间和完成所需的时间,如果超过规定时间完成,每超过一天就会扣1分,问怎样安排做作业的顺序才能使得所扣的分最小(相同答案输出字典序较小小的答案)

思路:用二进制压缩状态,比如110,表示第二门和第三门课程完成,第一门课程没有完成。我们的dp[i]意思是在i这个状态下能够扣除最低的分数。因为还要记录路径,我们的dp用结构体记录他的上一个状态,以及完成该状态的时间,还有完成这个状态前所做的科目(为了回溯路径用)。

注意:答案要求我们输出字典序最小,要怎么完成呢?题目给了输入是名称字典序升序排列的。我们可以在判断最小值时加一个等于,让字典序大的放在后面。

///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<bitset>
#include<set>
#include<stack>
#include<map>
#include<list>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;

struct node
{
    string x;
    int up;     ///科目的截至时间
    int cost;   ///花费天数
}work[20];

struct xx
{
    int state;  ///达到这个状态完成的科目
    int time;   ///完成这个状态的时间
    int pre;    ///上一个状态(用于记录路径)
    int score;  ///所扣除的分数
}dp[1<<15];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,limit;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            cin>>work[i].x>>work[i].up>>work[i].cost;
        dp[0]=xx{0,0,0,0};  ///初始化
        limit=(1<<n)-1;     ///状态上限
        for(int i=1;i<=limit;i++)   ///枚举状态
        {
            dp[i].score=INF;
            for(int j=0;j<n;j++)    ///枚举科目
            {
                if(i>>j&1)          ///判断当前状态是否已经完成了科目j
                {
                    int past=i-(1<<j);  ///未完成科目j的上一个状态
                    int value=max(dp[past].time+work[j].cost-work[j].up,0);///扣除分数最低为0
                    if(dp[past].score+value<=dp[i].score)   ///判断有等于,将字典序的放在后面
                        dp[i]=xx{j,dp[past].time+work[j].cost,past,dp[past].score+value};
                }
            }
        }
        vector<int>ans;
        cout<<dp[limit].score<<endl;
        while(limit)    ///利用状态回溯
        {
            ans.push_back(dp[limit].state);
            limit=dp[limit].pre;
        }
        int d=ans.size();
        for(int i=d-1;i>=0;i--)
            cout<<work[ans[i]].x<<endl;
    }
    return 0;
}