题意 有n个作业要做 给你每个作业的最后期限 和做完这个作业需要的时间 作业每超过最后期限一天就会扣一分 只能把一个作业做完了再做另一个作业 问做完所有作业至少扣多少分
作业最多只有15个 看到这个数字容易想到是状态压缩 dp[i]表示i对应状态的最小扣分 i转换为二进制后为1的位表明该位对应的作业已经做了 为0的位没做 那么dp[i] = min{dp[k] + cost | k为将某一位变成1后等于 i 的状态}
由于要打印路径 所有还需要记录每个状态的上一个状态pre
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 16, M = 1 << N;
int d[N], c[N], n;
int dp[M], pre[M], t[M];
char s[N][105];
void print(int k)
{
if(k == 0) return;
print(pre[k]);
k -= pre[k];
for(int i = 0; i < n; ++i)
if(k & 1 << i) puts(s[i]);
}
int main()
{
int T, m, cost;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
for(int i = 0; i < n; ++i)
scanf("%s%d%d", s[i], &d[i], &c[i]);
memset(dp, 0x3f, sizeof(dp));
dp[0] = t[0] = 0; //边界 所有作业都没做的扣分为0
m = 1 << n;
for(int i = 1; i < m; ++i)
{
for(int j = 0; j < n; ++j)
{
if((i & 1 << j) == 0) continue;
int k = i - (1 << j);
t[i] = t[k] + c[j];
cost = t[i] > d[j] ? t[i] - d[j] : 0;
if(dp[k] + cost <= dp[i]) //'='保证字典序最小
{
dp[i] = dp[k] + cost;
pre[i] = k; //记录路径
}
}
}
printf("%d\n", dp[m - 1]);
print(m - 1); //打印路径
}
return 0;
}
2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
2 Computer Math English 3 Computer English MathHintIn the second test case, both Computer->English->Math and Computer->Math->English leads to reduce 3 points, but the word "English" appears earlier than the word "Math", so we choose the first order. That is so-called alphabet order.
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 1074 Doing Homework(DP·状态压缩)
原文地址:http://blog.csdn.net/acvay/article/details/48051975