http://acm.hdu.edu.cn/showproblem.php?pid=1074
题目是给定n个科目(n <= 15)然后每个科目有最迟完成时间和需要多少天去完成。
现在要你安排一个顺序去做这些科目,使得扣分最小,要求输出字典序最小的解。
考虑用dp[i]表示完成了i的二进制那些科目时,所需的最小扣分。比如i(1001)就是完成了第1科和第四科。
那么枚举这样的每一个状态,再枚举每一个科目,如果当前这个状态还没有完成这个科目的话,就是(i & (1 << j)) == 0的话。
就可以进行转移了。可以用dp记录很多信息,包括当前状态的前一个状态(用于记录路径)和当前状态是选了哪一个科目(每一个新状态完成一个科目)和完成了当前状态的那些科目后,所需的最小扣分。和完成了当前状态的那些科目后,用了多少时间(这个用来记录后面枚举新科目的时候,是否会扣分)
其实你想维护什么,dp那里都可以记录。关键是转移的时候要按照扣分的多少来转移就是了。
如果从10001枚举到10011所需的扣分比从10010枚举到10011所需的最小扣分要小,
那么就要更新了,但是反过来,如果是相等呢?
相等的话,是不用变的,
因为答案需要的是最小字典序解
从10001枚举到10011
就是先做1和5,再做4
从10010枚举到10011
就是先做1和4,再做5
他们的cost相同,但是明显下面的字典序比较小(因为题目已经排好序)
所以,是不用变了
最后,dp数组要开到 1 << 15
一开始开了15,一直TLE

#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> struct nodeInformation { char name[100 + 20]; int dead; int need; }a[15 + 20]; struct nodeDp { int pre; int cur; //当前这个是什么 int cost; //记录扣多少分 int tim; //什么时候完成了这个状态 }dp[1 << 16]; void show(int val) { if (val == 0) return; show(dp[val].pre); printf("%s ", a[dp[val].cur].name); } void work() { int n; scanf("%d", &n); for (int i = 0; i < n; ++i) { scanf("%s%d%d", a[i].name, &a[i].dead, &a[i].need); } int end = 1 << n; memset(dp, 0x3f, sizeof dp); dp[0].cost = 0; dp[0].pre = -inf; dp[0].tim = 0; //一科都没完成的状态 dp[0].cur = -inf; for (int i = 0; i < end; ++i) { //枚举每一个状态 for (int j = 0; j < n; ++j) { if ((i & (1 << j)) == 0) { //如果没完成到这个科目,才能转移 int newState = i | (1 << j); int dayTofinish = dp[i].tim + a[j].need; int cost = dayTofinish - a[j].dead; if (cost < 0) cost = 0; //就是提前完成了,不用扣费 cost += dp[i].cost; if (cost < dp[newState].cost) { //现在这样花费比以前的小 dp[newState].cost = cost; dp[newState].cur = j; dp[newState].pre = i; //i这个状态 dp[newState].tim = dayTofinish; } } } } printf("%d ", dp[end - 1].cost); show(end - 1); } int main() { #ifdef local freopen("data.txt","r",stdin); #endif int t; scanf("%d", &t); while (t--) work(); return 0; }