题意 有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