-
Doing Homework
- HDU - 1074
- 枚举所有 作业完成状态
- 初始状态0末状态(1<<n)-1
- 第一层i枚举各种状态
- 第二层j查找当前i状态下第一个没完成的作业
- 然后k循环查找一下当前完成的作业把时间记录求和来 判断 找到的这个未完成的作业 到底是怎么罚时的
- dp更新i当前状态和把j位置完成的状态,并且更新前缀数组来记录罚时最少的排列方式。。
- 最终所有状态 会枚举更新完成 输出时,因为 pre 数组记录的是 那个状态的十进制数字
- 而我们需要输出那个状态下完成的哪一门作业,所以 二进制判断 cur当前的状态与pre[cur]状态的区别
- 就知道这一步操作是完成的谁
- PS:二进制操作如果优先级不熟悉老老实实的加括号
-
#include<iostream> #include<cstring> using namespace std; #define maxn 100 #define inf 0x3f3f3f3f int n,t,dp[1<<20]; int pre[1<<20],cnt; struct node { string name; int last,sum; } work[maxn]; void print(int cur) { if(cur==0) return ; int order=0; for(int i=0; i<n; i++) { if((cur&(1<<i))!=0&&(pre[cur]&(1<<i))==0) { order=i; break; } } print(pre[cur]); cout<<work[order].name<<endl; } int main() { cin>>t; while(t--) { cin>>n; for(int i=0; i<n; i++) cin>>work[i].name>>work[i].last>>work[i].sum; memset(dp,inf,sizeof(dp)); dp[0]=0; for(int i=0; i<(1<<n); i++) { for(int j=0; j<n; j++) { if(i&(1<<j)) continue; cnt=0; for(int k=0; k<n; k++) if(i&(1<<k)) cnt+=work[k].sum; cnt+=work[j].sum; if(cnt>work[j].last) cnt-=work[j].last; else cnt=0; if(dp[i|(1<<j)]>dp[i]+cnt) { dp[i|(1<<j)]=dp[i]+cnt; pre[i|(1<<j)]=i; } } } cout<<dp[(1<<n)-1]<<endl; print((1<<n)-1); } return 0; }
Doing Homework-状压DP
最新推荐文章于 2021-10-05 23:02:00 发布