标签:nat should 字典 bsp col 状态 help home iss
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 14600 Accepted Submission(s): 7070
2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
2 Computer Math English 3 Computer English Math
作业就要做不完了,每项作业(已经按照字典序排好)都有一个花费时间和限定时间,在限定时间之后在交的作业,每天扣一分,现在扣分最小值和相应的作业顺序(相同最小值时,以字典序最小的情况输出)
注意到最多只有15个作业,所以可以利用一个二进制数来表示当前的完成情况:比如111是全完成,101是第二个没完成
假如有7个作业,那么二进制就是 1111111 也就是 2^7-1 即127 我们枚举从1到127 用dp[i]来表示达到当前状态所扣分数的最小值
然后j从后向前枚举单个作业(至于为什么从后向前之后再说),判断这个作业是不是在当前状态已经完成了的,比如101,就是第一个作业和第三个作业是已经完成了的,那么当前的状态就可以从前一个状态转化过来,比如101 就可以从100或者001转化过来 这样就可以进行更新了,显然的 dp[i]=max(dp[i],dp[前一个状态]+a[j])
现在可以解释为什么从后向前遍历单个作业了,因为根据上面的转移方程,我们可以看出来当前状态是在完成这个作业之后达到的,也就是说,这个作业是最后完成的,而题目中要求,如果遇到最小值相同的时候,要以字典序最小的方案输出,所以必须要从后往前遍历
当然,要输出做题顺序,就要每次都记录当前状态的上一个状态是什么,以及当前完成了什么作业。
#include <bits/stdc++.h> using namespace std; typedef struct { string name; int dday; int cost; }homework; struct { int pre; int name; int vul; int time; }dp[1<<15]; homework a[105]; int tot,t,n,i,j; int main() { cin>>t; while(t--) { cin>>n; memset(dp,0,sizeof(dp)); for(i=0;i<n;i++) { cin>>a[i].name>>a[i].dday>>a[i].cost; } tot=1<<n; for(i=1;i<tot;i++) { dp[i].vul=0x7fffff; for(j=n-1;j>=0;j--) { int temp=1<<j; if(temp&i) { int s=dp[i-temp].time+a[j].cost-a[j].dday; if(s<0) s=0; if(dp[i].vul>dp[i-temp].vul+s) { dp[i].pre=i-temp; dp[i].name=j; dp[i].vul=dp[i-temp].vul+s; dp[i].time=dp[i-temp].time+a[j].cost; } } } } cout<<dp[tot-1].vul<<endl; i=tot-1; stack<int>q; while(dp[i].time) { q.push(dp[i].name); i=dp[i].pre; } while(!q.empty()) { cout<<a[q.top()].name<<endl; q.pop(); } } }
HDU 1074 Doing Homework (状压DP)
标签:nat should 字典 bsp col 状态 help home iss
原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/11355657.html