HDU 1074 状态压缩dp

来源:互联网 发布:m文件传入double数据 编辑:程序博客网 时间:2024/06/06 16:52

题意 :就是说有n门课程作业,每一门课程作业都有一个截止时间和完成作业所需要的时间,超出截止时间再交作业会被扣分,问你最少扣多少分。

题解 :首先我们发现,作业的数目最大只有15,如果纯暴力的话,需要 15 ! 显然 时间复杂度不可以接受,这个时候就要想能不能状态压缩一下,把15!降到 2^15 * 15 这种复杂度,这样的话就不难想到状态压缩dp了 (可以思考一下,其实状态压缩的好处就在于它仅仅用 2 ^ 15 这样的复杂度遍历了可能的所有情况这种聪明的枚举方法直接可以使得序列变成任何顺序啊) 然后就是需要记录状态了

dp (i) i 是 (0 ~ (1 << 15))表示已经做完了哪些课的最小处罚我们不仅仅需要记录 dp (i) 还需要记录 time (i) 表示已经过去的时间  还有 pos (i) 因为它让你记录路径。
#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <string>#define ll long longusing namespace std;const int INF = 1e9 + 7;const int maxn = (1 << 15);int dp[maxn] = {0};int tim[maxn] = {0};int pos[maxn] = {0};int res[20] = {0};struct node {    string s;    int need,dead;}val[20];int main () {    ios_base :: sync_with_stdio(false);    int T;    cin >> T;    while (T --) {        int n;        cin >> n;        for (int i = 0;i < n; ++ i) {            cin >> val[i].s >> val[i].dead >> val[i].need;        }        for (int i = 0;i < maxn; ++ i) {            dp[i] = INF;            tim[i] = INF;            pos[i] = 0;        }        dp[0] = 0;        tim[0] = 0;        for (int i = 0;i < (1 << n); ++ i) {            for (int j = 0;j < n; ++ j) {                if ((((1 << j) & i) == 0)) {                    int cost = tim[i] + val[j].need - val[j].dead;                    cost = max (cost,0);                    if (cost + dp[i] < dp[i + (1 << j)]) {                        tim[i + (1 << j)] = tim[i] + val[j].need;                        dp[i + (1 << j)] = cost + dp[i];                        pos[i + (1 << j)] = j;                    }                }            }        }        int u = (1 << n) - 1;        int cnt = 0;        while (u) {            res[cnt] = pos[u];            u -= (1 << res[cnt]);            cnt ++;        }        cout << dp[(1 << n) - 1] << endl;        for (int i = cnt - 1;i >= 0; -- i) {            cout << val[res[i]].s << endl;        }    }    return 0;}
原创粉丝点击