HDU 1074 Doing Homework (状态压缩DP)

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.

 

View Code
  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 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值