Doing Homework
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3572 Accepted Submission(s): 1417
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.

1 /* 2 状态压缩DP 3 因为只有15个课程,用15位的二进制表示课程的完成状态,1表示完成,0表示未完成, 4 既假定有4门课程,1100表示的是第4门和第3门课是完成的,也就是说可以用12这个 5 十进制数来表示完成了第4和第3门课这个状态。那么15门课程,如果表示全部都完成 6 了,那么只需用32767来表示。 7 8 二进制操作: 9 (1)i & j:j为第j门课,则这个操作表示的是i这个状态是否包含了j,也就是得到 10 i和j的相同之处。比如1011 & 0010 = 0010(!=0),说明i是包含j的。相同部分 11 就是j。 12 13 (2)i ^ j: 对于i和j两个不同的状态,该操作的结果是得到i和j的不同之处。 14 比如1011 ^ 0010 = 1001。说明了i这个状态除了j之外,还有第4门和第1门 15 是完成的。这跟&操作恰好相反。 16 17 PS: i | j:将i和j两个状态合并,比如1011 & 0100 = 1111; 18 19 15MS 664K 20 */ 21 22 #include <set> 23 #include <map> 24 #include <stack> 25 #include <queue> 26 #include <vector> 27 #include <cmath> 28 #include <cstdio> 29 #include <cstring> 30 #include <iostream> 31 #include <string> 32 #include <algorithm> 33 //#define SIZE 34 //#define inf 35 //#define mod 36 37 using namespace std; 38 39 typedef __int64 Int; 40 typedef long long ll; 41 typedef unsigned long long ull; 42 43 const double PI = acos(-1.0); 44 const double eps = 1e-8; 45 46 struct Work //每件工作包括名字,截止时间,完成需要的时间 47 { 48 char name[105]; 49 int deadline; 50 int cost; 51 }work[20]; 52 53 struct node //状态,pre是上一个状态,res是需要扣的分,cost是达到当前状态需要花费的时间 54 { 55 int pre; 56 int res; 57 int cost; 58 }dp[40005]; 59 60 int N; 61 62 void out(int state) //打印路径 63 { 64 if(state > 0) 65 { 66 out(dp[state].pre); 67 int t = dp[state].pre; 68 int ans = t ^ state; //找出当前状态和上一状态的不同之处 69 int idx = 0; 70 while(ans > 0) //找出该十进制数在二进制表示下,1出现在什么位置,因为1代表完成了哪个课程。 71 { 72 idx ++; 73 ans >>= 1; 74 } 75 printf("%s\n",work[idx].name); 76 } 77 } 78 79 int main() 80 { 81 int Case; 82 scanf("%d",&Case); 83 while(Case--) 84 { 85 scanf("%d",&N); 86 for(int i=1; i<=N; i++) 87 scanf("%s%d%d",work[i].name,&work[i].deadline,&work[i].cost); 88 int Max = 1 << N; 89 Max -= 1; //因为1<<N使最大状态变成了N+1位的二进制,减1得到全是1的N位二进制 90 dp[0].cost = 0; 91 dp[0].pre = -1; 92 dp[0].res = 0; 93 for(int i=1; i<=Max; i++) 94 { 95 dp[i].cost = 0; 96 dp[i].pre = -1; 97 dp[i].res = 0xfffffff; 98 for(int j=0; j<N; j++) 99 { 100 int cur = 1 << j; //枚举每一门课程 101 if(i & cur) //如果当前状态包含了该课程 102 { 103 dp[i].cost = dp[i^cur].cost + work[j+1].cost; 104 int reduce = dp[i].cost - work[j+1].deadline; 105 if(reduce < 0) 106 reduce = 0; 107 reduce += dp[i^cur].res; 108 if(dp[i].res >= reduce) //因为题目中的课程输入已经保证是字典序,所以==的时候一样更新 109 { 110 dp[i].res = reduce; 111 dp[i].pre = i^cur; 112 } 113 } 114 } 115 } 116 printf("%d\n",dp[Max].res); 117 out(Max); 118 } 119 return 0; 120 }