状态压缩 之 hdu 1074 Doing Homework

来源:互联网 发布:任我行 陈奕迅 知乎 编辑:程序博客网 时间:2024/06/08 07:36
//  [9/11/2014 Sjm]/*hdu 1074 (状态压缩)dp[i]: 表示在 i 状态时的最优解 (i状态: i数值用二进制表示, 若二进制数第 n 位为1,代表第 n 个课程已被计算)思路: 详见代码注释(举几个简单例子模拟一下,可以明白的更清楚一些)*/
#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>#include <string>using namespace std;const int MAX = 1 << 16, MAX_N = 20, INF = 0x3f3f3f3f;int N;bool Vis[MAX];struct myNode {int nowTime; // 当前时间int pre; // 前一个状态int minReduce; // 被扣掉的分数} dp[MAX];struct mySubject {string name; // 课程名int deadline; // 最后期限int cost; // 所需要花费的时间} subject[MAX_N];int getPos(int x) {int pos = 0;while (x) {++pos;x >>= 1;}return (pos - 1);}void Output(int State) {if (0 == State) return;int nowSub = (State^dp[State].pre); // 为了获取当前课程是第几个 ==> getPos(nowSub)Output(dp[State].pre);cout << subject[getPos(nowSub)].name << endl;}void Solve() {memset(Vis, false, sizeof(Vis));for (int i = 0; i < N; ++i) dp[i].minReduce = INF;dp[0].nowTime = 0;dp[0].pre = -1;dp[0].minReduce = 0;Vis[0] = true;int finalState = (1<<N) - 1;for (int state = 0; state < finalState; ++state) {  // 遍历所有状态for (int subPos = 0; subPos < N; ++subPos) { // 在当前状态下加入subPos课程int sub = (1 << subPos);if (0 == (sub&state)) { // 判断当前subPos课程是否已经计算过,若没有则进行计算,否则需寻找其他课程int nowState = state | sub; // 计算过subPos课程后,所到达的新的状态int finish_nowState_Time = dp[state].nowTime + subject[subPos].cost; // 完成subPos课程后,整个状态所到达的时间int nowStateReduce = finish_nowState_Time - subject[subPos].deadline; if (nowStateReduce < 0) nowStateReduce = 0; // 仅仅因为subPos课程所需要被扣掉的分数nowStateReduce = dp[state].minReduce + nowStateReduce; // 完成subPos课程后,整个状态需要被扣掉的分数if (Vis[nowState]) { // 若新的状态之前到达过,则与完成subPos课程到达此状态时,所被扣掉的分数进行比较// 若之前到达该状态时,所被扣掉的分数 > 完成subPos课程到达此状态时,所被扣掉的分数// 则对该状态进行更新if (dp[nowState].minReduce > nowStateReduce) {dp[nowState].minReduce = nowStateReduce;dp[nowState].pre = state;dp[nowState].nowTime = finish_nowState_Time;}}else {// 若新的状态之前没有到达过,直接赋值更新Vis[nowState] = true;dp[nowState].minReduce = nowStateReduce;dp[nowState].pre = state;dp[nowState].nowTime = finish_nowState_Time;}}}}printf("%d\n", dp[finalState].minReduce); Output(finalState); // 递归输出所选择课程的顺序}int main() {//freopen("input.txt", "r", stdin);//freopen("output.txt", "w", stdout);int Case;scanf("%d", &Case);while (Case--) {scanf("%d", &N);for (int i = 0; i < N; ++i) {cin >> subject[i].name;scanf("%d %d", &subject[i].deadline, &subject[i].cost);}Solve();}return 0;}
0 0
原创粉丝点击