题目链接
快速VJ链接入口
题意:告诉你有N门课,以及每门课的截止时间和需要的学习时间,问的是,我们最少需要少上几天的课。
思路:当N只有15的时候,很容易想到的是状态压缩,但是,这个状态又表示的是什么?就是已经选好了做这些课的情况下,我们的需要的丢失的最少成绩,此时用DP表示,实现状态的转移。
我们去遍历所有的状态,分别是做完分别几门课后的状态压缩,然后,我们在做完的课中选取其中一门课,那么除去这门课,就是前一刻的状态,对于前一刻的状态,有其对应的已经学到的时间线——指的是前面的所有时间表都是排满的,如果现在学这门课比之前的状态下的会减少失分的话,那么,就现在选这门课,然后last(上一个状态也要更新),学这门课的时间需求也可能不一样的,所以时间线也要更新,同时,得分会不一样的,就是这个目的。
然而,处理的重点确实是个细节,WA了一发之后就发现了关键所在,我们考虑在更新新的课的时候,如果从第0门课向第N-1门课推去的话,其实,就是相当于后面的课已经选好了,我们只需要再增添前面的字典序在前的课就行了!当然是反了的!!!我们得尽可能的先选取上前面的课,然后再补上后面的课。这样就能做到字典序升序了。
记录前面的状态,以及前一个的值,然后,就是用dfs()跑一遍倒叙输出即可(因为是从满状态往前推去的)。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 15;
int N, tot; //tot是满状态情况:全都取
struct node
{
string name;
int Day_End, needs;
node(string a="", int b=0, int c=0):name(a), Day_End(b), needs(c) {}
}a[maxN];
struct IN_DP
{
int score, pre, ti, now_id;
IN_DP(int a=0, int b=0, int c=0, int d=0):score(a), pre(b), ti(c), now_id(d) {}
}dp[(1<<maxN) + 7];
void dfs(int pos)
{
if(!pos) return;
dfs(dp[pos].pre);
cout<<a[dp[pos].now_id].name<<endl;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &N);
for(int i=0; i<N; i++)
{
cin>>a[i].name; //输入按照字典序升序,输出也要按照字典序升序输出,我们取的话,得在最优的情况下选取最前面的
scanf("%d%d", &a[i].Day_End, &a[i].needs);
}
tot = (1<<N) - 1; //全部状态了,都已经取完的情况,满状态
memset(dp, 0, sizeof(dp));
for(int s=1; s<=tot; s++) //所有状态
{
dp[s].score = INF; //初始化扣分的情况
for(int i=N-1; i>=0; i--) //我们接下来是选择修学那门课,由于输出按字符串大小输出,故每次完成i的话,就要把i放在最后面
{
int tmp = (1<<i);
if(tmp & s)
{
int las = s - tmp; //目的就在于先取前面的值,对应i,从大数开始,这就可以保证其s(状态)的补集是从小数开始,而我们的状态从1开始,则即是从最前面的开始选取过来,保证字典序
int need = dp[las].ti + a[i].needs - a[i].Day_End; //所需要的时间:上一个状态的时间线已经到哪了、如果要学这门课的话,是需要额外多少时间(可能是多出来的时间就是指学不全)
if(need < 0) need = 0; //时间不可逆
if(dp[s].score > dp[las].score + need)
{
dp[s] = IN_DP(dp[las].score + need, las, dp[las].ti + a[i].needs, i);
}
}
}
}
printf("%d\n", dp[tot].score);
dfs(tot);
}
return 0;
}