HDU 1074 Doing Homework<<状压dp

题意

一个人要完成作业,给定作业的ddl和完成所需时间,超时扣分,要决定完成作业的顺序使得扣分最少

思路

暴力枚举需要n!次,不可取,但发现做完相同的题目时,用时是相同的,但扣分不同,就想到利用状态压缩,把做了哪几题的状态用1<<n的状态数记录,dp[i]表示状态为i时的扣分,最小化dp[i]

然后状态转移方程为$min(dp[i],dp[i-j]+reduce)$

代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int INF=0x3f3f3f3f;
 4 int dp[1<<16];
 5 int n,up;
 6 string sub[16];
 7 int ddl[16];
 8 int cost[16];
 9 int pre[1<<16];
10 int t[1<<16];
11 void op(int now)
12 {
13     if(!now)
14         return;
15     else{
16         op(now-(1<<pre[now]));
17         cout<<sub[pre[now]]<<endl;
18     }
19 }
20 int main()
21 {
22     int T;
23     cin>>T;
24     while(T--)
25     {
26         cin>>n;
27         up=1<<n;
28         for(int i=0;i<n;i++)
29         {
30             cin>>sub[i];
31             cin>>ddl[i]>>cost[i];
32         }
33         dp[0]=0;
34         t[0]=0;
35         for(int i=1;i<up;i++)//枚举所有状态
36         {
37             dp[i]=INF;//所有状态初始扣分为INF
38             for(int j=n-1;j>=0;j--)//枚举上一个做的作业,倒着枚举保证原本字典序大的在相同条件下后做
39             {
40                 int now=1<<j;
41                 if(!(i&now)) continue;
42                 int reduce=t[i-now]+cost[j]-ddl[j];//从j到达i的扣分
43                 if(reduce<0) reduce=0;
44                 if(dp[i-now]+reduce<dp[i])
45                 {
46                     t[i]=t[i-now]+cost[j];
47                     pre[i]=j;
48                     dp[i]=dp[i-now]+reduce;
49                 }
50             }
51         }
52         printf("%d\n",dp[up-1]);
53         op(up-1);//递归打印
54     }
55 }

后记

练习一下状压dp提升一下思维,顺便学习一下dp

posted @ 2018-12-03 09:31  computer_luo  阅读(108)  评论(0编辑  收藏  举报