HDU1074(KB12-D 状态压缩dp)

Doing Homework

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8756    Accepted Submission(s): 4065


Problem Description

Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test, 1 day for 1 point. And as you know, doing homework always takes a long time. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.
 

Input

The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=15) which indicate the number of homework. Then N lines follow. Each line contains a string S(the subject's name, each string will at most has 100 characters) and two integers D(the deadline of the subject), C(how many days will it take Ignatius to finish this subject's homework). 

Note: All the subject names are given in the alphabet increasing order. So you may process the problem much easier.
 

Output

For each test case, you should output the smallest total reduced score, then give out the order of the subjects, one subject in a line. If there are more than one orders, you should output the alphabet smallest one.
 

Sample Input

2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
 

Sample Output

2 Computer Math English 3 Computer English Math

Hint

In the second test case, both Computer->English->Math and Computer->Math->English leads to reduce 3 points, but the word "English" appears earlier than the word "Math", so we choose the first order. That is so-called alphabet order.
 
 1 //2017-03-28
 2 //状态压缩dp,sta的二进制所在位为1表示对应的作业已经处理,0表示未处理。sta低位对应为字典序小的课程。
 3 #include <iostream>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <stack>
 8 
 9 using namespace std;
10 
11 const int N = (1<<15)+10;
12 const int inf = 0x3f3f3f3f;
13 int pre[N];//pre[i]表示状态i由前一个状态转移来时放入的作业编号
14 int dp[N];//dp[i]表示达到状态i所扣的最少的分
15 int tm[N];//tm[i]表示到达状态i花费的最少时间
16 int order[20];//用于保存最后输出的课程序列
17 int n;
18 struct node
19 {
20     string name;
21     int d, c;
22 }work[20];
23 
24 int main()
25 {
26     int T;
27     cin>>T;
28     while(T--)
29     {
30         cin>>n;
31         for(int i = 0; i < n; i++)
32               cin>>work[i].name>>work[i].d>>work[i].c;
33         for(int sta = 1; sta < (1<<n); sta++)
34         {
35             dp[sta] = inf;
36             for(int j = n-1; j >= 0; j--)//为使序列倒序输出,从字典序大的作业开始枚举
37             {
38                 int fmsta = (1<<j);//表示当前状态sta可以由sta-fmsta状态转移而来。
39                 if(!(fmsta&sta))continue;//表示该sta-fmsta不能转移到sta,继续
40                 int score = tm[sta-fmsta] - (work[j].d - work[j].c);//tm[sta-fmsta]表示转移前状态所花费的最小时间,(work[j].d - work[j].c)表示work[j]能开始的最晚时间。
41                 if(score < 0)score = 0;//若转移前时间比最晚开始时间早,所需要扣的分为0
42                 if(dp[sta] > dp[sta-fmsta]+score){
43                     dp[sta] = dp[sta-fmsta]+score;
44                     tm[sta] = tm[sta-fmsta] + work[j].c;
45                     pre[sta] = j;
46                 }
47             }
48         }
49         cout<<dp[(1<<n)-1]<<endl;
50         int cnt = 0, pos = (1<<n)-1;
51         stack<int> s;
52         while(pos)
53         {
54             s.push(pre[pos]);
55             pos = pos-(1<<pre[pos]);
56         }
57         while(!s.empty())
58         {
59             cout<<work[s.top()].name<<endl;
60             s.pop();
61         }
62     }
63 
64     return 0;
65 }
原文地址:https://www.cnblogs.com/Penn000/p/6636961.html