HDU 1074 Doing Homework(DP状态压缩)

时间:2022-09-26 00:32:50

题意:有n门功课需要完成,每一门功课都有时间期限以及你完成所需要的时间,如果完成的时间超出时间期限多少单位,就会被减多少学分,问以怎样的功课完成顺序,会使减掉的学分最少,有多个解时,输出功课名字典序最小的一个。

作业最多只有15个,容易想到是状态压缩  dp[i]表示i对应状态的最小扣分  i转换为二进制后为1的位表明该位对应的作业已经做了,为0的位没做。

dp[i] = min{dp[k] + cost | k为将某一位变成1后等于 i 的状态} 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 
 8 const int N = 16;
 9 struct Node
10 {
11     char str[109];
12     int want, need;
13 }node[N];
14 
15 struct DP // 状态
16 {
17     int now, sum, pre, pos; // 当前状态的时间,总惩罚,前一个选择,当前选择
18 }dp[1<<N];
19 
20 void put_ans(int x)
21 {
22     if(dp[x].pre != -1)
23     {
24         put_ans(dp[x].pre);
25         printf("%s\n", node[dp[x].pos].str);
26     }
27 }
28 
29 int main () {
30 
31     int T;
32     scanf("%d",&T);
33     while(T--)
34     {
35         int n;
36         scanf("%d",&n);
37         for(int i=0;i<n;i++)
38             scanf("%s%d%d", node[i].str, &node[i].want, &node[i].need);
39         dp[0].now = dp[0].sum = 0;
40         dp[0].pre = dp[0].pos = -1;
41         int m = (1<<n)-1;
42         for(int i=1; i<=m; i++)
43         {
44             dp[i].sum=0x3f3f3f3f;
45             for(int j=0; j<n; j++)
46             {
47                 if((1<<j) & i)
48                 {
49                     int k = i - (1<<j);
50                     int v = dp[k].now + node[j].need - node[j].want;
51                     v = max(v, 0);
52                     if(dp[i].sum >= dp[k].sum+v)//必须有等号,这样保持字典序
53                     {
54                         dp[i].sum = dp[k].sum + v;
55                         dp[i].now = dp[k].now + node[j].need;
56                         dp[i].pre = k;
57                         dp[i].pos = j;
58                     }
59                 }
60             }
61         }
62         printf("%d\n", dp[m].sum);
63         put_ans(m);
64     }
65     return 0;
66 }