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