HDU 1074 状态压缩dp

题意 :就是说有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 long
using 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值