状态压缩DP Doing Homework
Posted Vincent_0000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状态压缩DP Doing Homework相关的知识,希望对你有一定的参考价值。
题目提交点
题目分析 + 自我总结
- 题意大意
给作业做的时间排序,使得扣除的分数最小,并输出方案。
- 分析题型
我考虑的是01背包,后面发现01背包无法实现都选择的情况,前后都冲突了,导致这个题目没有做出来。
对于正确思考这个题目,应该这么去做:
查看数据范围,n很小,可以直接排除背包问题,像这种题目,显然不会出数据范围这么小的背包问题。
遇到这种时候就要先想想暴力怎么写。
我们使用DFS, 每次都遍历之前没有遍历过的点,保存当前所扣除的分数,该分数等于,之前所以走过所扣除的分数加上现在的分数,现在的分数等于已经走过路径所花费的时间+做完这个作业需要的时间 - 时间期限。
遍历完所有的点之后更新答案和路径。
这种写法显然会超时,而且是求最优的题目, 这种数据范围之内有没有可以相似的DP类型呢?
有,状态压缩DP。
所以尝试使用状态DP做这个题目,初步判断为状态压缩DP + 记录路径。
- DP优化
for (遍历所有情况)
对最后一个状态和前面一群状态进行分析(DP基本想法)
for(选择哪一个作业作为我们当前情况的最后一种情况) (逆序)
状态转移方程 f(当前情况) = min(f(当前情况), f(之前的分数) + 现在的分数)
第二个for循环需要逆序的原因是我们遍历结果是从后往前的,而题目给的字典序是从前往后排是依次增大的,与我们的路径相矛盾。
- 目标
f(全都选好的情况)
AC代码
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << ENDL
#define ENDL "\\n"
#define x first
#define y second
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int N = 15 + 5, M = (1 << 15) + 5, INF = 0x3f3f3f3f;
int f[M], D[N], C[N],v[M], last[M];
char s[N][105];
void print(int x) {
if (!x) return;
print(x - (1 << last[x]));
cout << s[last[x]] << ENDL;
}
int main() {
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
_for(i, 0, n) cin >> s[i] >> D[i] >> C[i];
int sz = 1 << n;
_for(i, 1, sz) {
f[i] = INF;
For(j, n - 1, 0) {
int k = 1 << j;
if (!(i & k)) continue;
int w = v[i - k] + C[j] - D[j];
if (w < 0) w = 0;
if (f[i] > f[i - k] + w) {
f[i] = f[i - k] + w;
v[i] = v[i - k] + C[j];
last[i] = j;
}
}
}
cout << f[sz - 1] << ENDL;
print(sz - 1);
}
return 0;
}
以上是关于状态压缩DP Doing Homework的主要内容,如果未能解决你的问题,请参考以下文章
状态压缩DP,附上例题(HDU - 1074 Doing Homework )
HDU 1074 Doing Homework 状态压缩DP