题目的意思:N门课程有作业,一个时间是最迟交的时间,一个是需要耗费多少时间来完成,到了期限,迟交多少,就扣多少分,求扣最少分的做作业的顺序。
N小于等于15,可以枚举所以的情况,数的二进制来表示各种情况。
对于集合编码成整数,可以看我的另一篇博客:点击打开链接
枚举每一门课程,S & (1 << i)表示第i门课程是否完成,为 1 就是完成了。
对于状态压缩DP还不是很熟,特别是位运算,很是蛋疼。
参考别人博客学习的。
下面的是AC的代码:
#include <iostream>
#include <cstring>
#include <string>
#include <stack>
using namespace std;
const int INF = 100000000;
struct data
{
string name;
int last, cost;
}Data[20];
struct DP
{
int time, score, pre, now;//time为该状态多出来的时间,score是扣的分,pre,now用来记录路径
}dp[1 << 15 + 1];
int main()
{
int t, n, i, end;
cin >> t;
while(t--)
{
memset(dp, 0, sizeof(dp));//初始化
cin >> n; //输入
for(i = 0; i < n; i++)
cin >> Data[i].name >> Data[i].last >> Data[i].cost;
end = 1 << n;
for(int S = 1; S < end; S++)//枚举所以的状态
{
dp[S].score = INF;
for(i = n - 1; i >= 0; i--) //每一门课程
{
int temp = 1 << i;
if(S & temp) //判断第i门课程是否完成
{
int a = S - temp; //集合S去掉 i,也就是第i门课程没完成,也就是上一个状态
int s = dp[a].time + Data[i].cost - Data[i].last;
if(s < 0)
s = 0;
if(s + dp[a].score < dp[S].score) //分数小于现在的状态
{
dp[S].score = s + dp[a].score;
dp[S].pre = a; //记录路径
dp[S].now = i; //记录路径
dp[S].time = dp[a].time + Data[i].cost;
}
}
}
}
stack <int>Stack;
cout << dp[end - 1].score << endl;
int res = end - 1;
while(res) //取路径
{
Stack.push(dp[res].now);
res = dp[res].pre;
}
while(!Stack.empty()) //输出
{
cout << Data[Stack.top()].name << endl;
Stack.pop();
}
}
return 0;
}