状态压缩 之 hdu 1074 Doing Homework

//  [9/11/2014 Sjm]
/*
hdu 1074 (状态压缩)
dp[i]: 表示在 i 状态时的最优解 
(i状态: i数值用二进制表示, 若二进制数第 n 位为1,代表第 n 个课程已被计算)
思路: 详见代码注释(举几个简单例子模拟一下,可以明白的更清楚一些)
*/
 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 using namespace std;
 7 const int MAX = 1 << 16, MAX_N = 20, INF = 0x3f3f3f3f;
 8 int N;
 9 bool Vis[MAX];
10 
11 struct myNode {
12     int nowTime; // 当前时间
13     int pre; // 前一个状态
14     int minReduce; // 被扣掉的分数
15 } dp[MAX];
16 
17 struct mySubject {
18     string name; // 课程名
19     int deadline; // 最后期限
20     int cost; // 所需要花费的时间
21 } subject[MAX_N];
22 
23 int getPos(int x) {
24     int pos = 0;
25     while (x) {
26         ++pos;
27         x >>= 1;
28     }
29     return (pos - 1);
30 }
31 
32 void Output(int State) {
33     if (0 == State) return;
34     int nowSub = (State^dp[State].pre); // 为了获取当前课程是第几个 ==> getPos(nowSub)
35     Output(dp[State].pre);
36     cout << subject[getPos(nowSub)].name << endl;
37 }
38 
39 void Solve() {
40     memset(Vis, false, sizeof(Vis));
41     for (int i = 0; i < N; ++i) dp[i].minReduce = INF;
42     dp[0].nowTime = 0;
43     dp[0].pre = -1;
44     dp[0].minReduce = 0;
45     Vis[0] = true;
46     int finalState = (1<<N) - 1;
47     for (int state = 0; state < finalState; ++state) {  // 遍历所有状态
48         for (int subPos = 0; subPos < N; ++subPos) { // 在当前状态下加入subPos课程
49             int sub = (1 << subPos);
50             if (0 == (sub&state)) { // 判断当前subPos课程是否已经计算过,若没有则进行计算,否则需寻找其他课程
51                 int nowState = state | sub; // 计算过subPos课程后,所到达的新的状态
52                 int finish_nowState_Time = dp[state].nowTime + subject[subPos].cost; 
53                 // 完成subPos课程后,整个状态所到达的时间
54                 int nowStateReduce = finish_nowState_Time - subject[subPos].deadline; 
55                 if (nowStateReduce < 0) nowStateReduce = 0; 
56                 // 仅仅因为subPos课程所需要被扣掉的分数
57                 nowStateReduce = dp[state].minReduce + nowStateReduce; 
58                 // 完成subPos课程后,整个状态需要被扣掉的分数
59                 if (Vis[nowState]) { 
60                     // 若新的状态之前到达过,则与完成subPos课程到达此状态时,所被扣掉的分数进行比较
61                     // 若之前到达该状态时,所被扣掉的分数 > 完成subPos课程到达此状态时,所被扣掉的分数
62                     // 则对该状态进行更新
63                     if (dp[nowState].minReduce > nowStateReduce) {
64                         dp[nowState].minReduce = nowStateReduce;
65                         dp[nowState].pre = state;
66                         dp[nowState].nowTime = finish_nowState_Time;
67                     }
68                 }
69                 else {
70                     // 若新的状态之前没有到达过,直接赋值更新
71                     Vis[nowState] = true;
72                     dp[nowState].minReduce = nowStateReduce;
73                     dp[nowState].pre = state;
74                     dp[nowState].nowTime = finish_nowState_Time;
75                 }
76             }
77         }
78     }
79     printf("%d
", dp[finalState].minReduce); 
80     Output(finalState); // 递归输出所选择课程的顺序
81 }
82 
83 int main() {
84     //freopen("input.txt", "r", stdin);
85     //freopen("output.txt", "w", stdout);
86     int Case;
87     scanf("%d", &Case);
88     while (Case--) {
89         scanf("%d", &N);
90         for (int i = 0; i < N; ++i) {
91             cin >> subject[i].name;
92             scanf("%d %d", &subject[i].deadline, &subject[i].cost);
93         }
94         Solve();
95     }
96     return 0;
97 }

 
原文地址:https://www.cnblogs.com/shijianming/p/4140805.html