原题链接

考察:状压dp

错误思路:

        贪心思想,每个作业用ed-cost = st排序,输出路径就是排序后的路径.

错误数据
1
2
a 6 14
b 10 7

很明显可以发现如果数据中出现了ed-cost <0就会错误,按贪心思路是先选a,但是最优解是先选b.很明显先做完能及时做完的可以减少减去的分数.

正确思路:

       状压dp,状压dp实际上就是枚举所有可行的方案.但这道题我们需要记录路径,也就是记录由k->i的k状态.最后递归输出.这里可以参考 AcWing 1076的记录路径,将dp数组换成结构体,记录上一状态.

       这里n范围很小,属于状压dp的可行范围.

       这道题是状压dp,实际是在枚举所有到达终点的方式.与背包dp不同的是,这里不是组合问题,而是排列问题,并且n很小,最后每个都要选.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 using namespace std;
 6 const int N = 15;
 7 struct HW{
 8     int ed,cost;
 9     string s;
10 }hw[N];
11 struct F{
12     int cost,st,pre,pos;//花费,开始时间,上一个状态 
13 }f[(1<<N)+10];
14 int n;
15 void inits()
16 {
17     f[0].pos =f[0].pre = -1;
18     for(int i=1;i<1<<n;i++)
19     {
20         f[i].pre = -1;
21         f[i].cost = 0x3f3f3f3f;
22         f[i].st = 0;
23         f[i].pos = -1;
24     }
25 }
26 void dfs(int state)
27 {
28     if(f[state].pre!=-1)
29     {
30         int v = f[state].pre;
31         dfs(v);
32     }
33     if(f[state].pos!=-1)
34       printf("%s\n",hw[f[state].pos].s.c_str());
35 }
36 int main()
37 {
38     int T;
39     scanf("%d",&T);
40     while(T--) 
41     {
42         scanf("%d",&n);
43         for(int i=0;i<n;i++)
44             cin>>hw[i].s>>hw[i].ed>>hw[i].cost;
45         inits();
46         for(int i=1;i<1<<n;i++)
47         {
48             for(int j=n-1;j>=0;j--)
49               if(i>>j&1)
50               {
51                    int k = i-(1<<j);
52                    int cost = max(f[k].st+hw[j].cost-hw[j].ed,0);
53                    if(f[k].cost+cost<f[i].cost)
54                    {
55                        f[i].pre = k;
56                        f[i].cost = f[k].cost+cost;
57                        f[i].st = f[k].st+hw[j].cost;
58                        f[i].pos = j;
59                  }
60               }
61         }
62         printf("%d\n",f[(1<<n)-1].cost);
63         dfs((1<<n)-1);
64     }
65     return 0;
66 }