您的位置:首页 > 其它

HDU 1074 状态压缩dp

2017-10-08 14:06 316 查看

题意 :就是说有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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp