题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074
题目描述: 给你所有课程的截止时间和工作时长, 一次只能做一种作业, 问最少罚时几天 N <= 15
解题思路: 由于N很小, 所以第一反应就是状压DP, 我们可以用一个15位二进制数来表示各个课程做完还是没做完, 然后从 S 从 1 到 1 << N 枚举 i 从 1 到 N 枚举, 如果S & (1<<i) 有效则说明i 属于情况 S, 这样我们从上一步S - 1 << i 转移过来就可以, 记录路径就是每当出现答案的更新就将此时的状态和当前处理的位数记住, 压入栈中, 最后再倒着打出来
代码:
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <map> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <set> #include <iterator> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; const int maxn = 20; int deadline[maxn]; int cost[maxn]; string name[maxn]; const int INF = 0x3fffffff; set<string> ans; struct node { int time, score, pre, now; }; node dp[1<<15]; set<string>::iterator it; int main() { int t; cin >> t; while( t-- ) { ans.clear(); memset(dp, 0, sizeof(dp)); int n; cin >> n; for( int i = 0; i < n; i++ ) { cin >> name[i] >> deadline[i] >> cost[i]; } int end = 1 << (n); // cout << end << endl; for( int s = 1; s < end; s++ ) { dp[s].score = INF; for( int i = n-1; i >= 0; i-- ) { int temp = 1 << i; if( temp & s ) { int past = s- temp; int st = dp[past].time + cost[i] - deadline[i]; if( st < 0 ) st = 0; if( st + dp[past].score < dp[s].score ) { dp[s].score = st + dp[past].score; dp[s].pre = past; dp[s].now = i; dp[s].time = dp[past].time + cost[i]; } } } } stack<int> S; int tem = end-1; cout << dp[tem].score << endl; while(tem) { S.push(dp[tem].now); tem = dp[tem].pre; } while(!S.empty()) { cout << name[S.top()] << endl; S.pop(); } } return 0; }
思考: 自己一开始只知道是状压DP, 具体该怎么做还是不知道, 要接触各种DP
时间: 2024-11-01 22:41:25