hdu1074(状压)

来源:互联网 发布:uml画图软件 编辑:程序博客网 时间:2024/06/03 17:34
/*translation:给出n门作业,没门作业有期限和完成所需的时间。超过期限每一天就扣掉一分。求最少扣掉多少分。并按字典序给出作业的完成顺序。solution:状压dp仔细观察题意可以发现就是求作业的某一种排列顺序使得满足最优解。所以用动态规划的状态表示一定涉及到集合。又考虑到数据量不多。所以可以用状态压缩。note:1:注意枚举作业状态时候的顺序,见代码注释。# 最初的思路是这样定义状态的dp[i][j][k]:表示在第k天完成了i项作业,且最后一项作业为j的最小已拖延天数。  则状态转移方程:dp[i][j][k]=min(dp[i-1][t][k-ci])+k-dj。正确与否未知,待补。。。。。。* 注意这道题的dp数组表示方式。开太多维的数组没必要。* 涉及到集合的表示且数据量小的动规一般考虑状压。date:2016.10.30*/#include <iostream>#include <cstdio>#include <string>#include <vector>#include <cstring>using namespace std;const int maxn = 15;const int INF = 1e9;struct Subject{string name;int d, c;Subject(string n, int d, int c):name(n),d(d),c(c){}Subject(){}} sub[maxn];struct DP{int current, pre, score, time;//当前状态完成的作业编号,先前一个状态的编号,到当前状态为止的最少惩罚,到当前状态的时间} dp[1 << maxn + 5];//dp[s]表示当前状态编号为s的各种信息。int n;bool vis[1 << maxn + 5];int main(){freopen("in.txt", "r", stdin);int T;cin >> T;while(T--){cin >> n;for(int i = 0; i < n; i++)cin >> sub[i].name >> sub[i].d >> sub[i].c;//dp[0].pre = -1;for(int s = 1; s < (1 << n); s++){//枚举当前的状态dp[s].score = INF;for(int i = n-1; i >= 0; i--){//枚举当前状态的最后一项作业是什么,由于要求字典序,所以当然要从后面开始遍历int tmp = (1 << i);if(tmp & s){int pre_s = s - tmp;int st = dp[pre_s].time + sub[i].c - sub[i].d;if(st < 0)st = 0;if(st + dp[pre_s].score < dp[s].score){dp[s].score = st + dp[pre_s].score;dp[s].current = i;dp[s].pre = pre_s;dp[s].time = dp[pre_s].time + sub[i].c;}}}}cout << dp[(1 << n)-1].score << endl;vector<int> ans;int tmp = (1<<n)-1;while(tmp){ans.push_back(dp[tmp].current);tmp = dp[tmp].pre;}int len = ans.size();for(int i = len-1; i >= 0; i--){cout << sub[ans[i]].name << endl;}}    return 0;}

0 0