标签:images amp back input home alpha 题意 namespace ace
可以说是第一道状压DP题,至少感觉这道题目还是挺简单的,不算很难理解;
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
题意:
有n门课,每门课有截止时间(deadline)和完成所需的时间,如果超过规定时间完成,每超过一天就会扣1分,问怎样安排做作业的顺序才能使得所扣的分最小;
题解:
首先,dp思想:
假设dp[ _ , _ , _ , …… , _ , _ , _ ]记录了:n门课,在一些完成了,一些未完成的状态下,当前已经花去的时间(time),以及,当前已经被扣掉的最少分数(rs);
例如:有3门课,那么dp[0,0,0]代表了三门课作业还未做完的状态,dp[0,1,1]代表第二门和第三门的作业已经做完,第一门课作业还没做完的状态;
那么,我们状态转移方程:
也就是说,dp[…1…]表示当前状态下第k门课已完成;
那么,在dp[…0…]状态下,“已花费的时间 + 完成第k门课所需的时间 - 这门课的deadline”表示当前状态下开始做第k门课的作业,会导致扣多少分(记为red_sco)。
如果red_sco + dp[…0…].rs 比 dp[…1…].rs 小,说明我们可以更新一下dp[…1…],它的rs可以更小;
然后,由于一门课的作业,只有做完和还没做完两个状态,所以我们dp[ _ , _ , _ , …… , _ , _ , _ ]里的n个数字,合起来看就是一个二进制数;
那么我们把它转换成十进制,其实并不影响实际的状态转移操作,故我们可以对这个状态进行压缩(原本n位的二进制数字可以压缩的很小位数的十进制数),即状压DP;
把状压DP讲的如此的清晰,简直泼妇爱科特,忍不住自恋一把……
AC代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<stack> 4 #define INF 0x3f3f3f3f 5 using namespace std; 6 int n;//n门课 7 struct Course{ 8 string name; 9 int cost,deadline; 10 }course[16]; 11 12 struct DP{ 13 int time,rs; 14 int now,pre;//用以记录做作业的顺序 15 }dp[1<<15]; 16 17 int main() 18 { 19 int t; 20 scanf("%d",&t); 21 while(t--) 22 { 23 scanf("%d",&n); 24 for(int i=0;i<n;i++) cin>>course[i].name>>course[i].deadline>>course[i].cost; 25 26 int ed_state=(1<<n)-1;//所有作业都做完的状态 27 28 dp[0].time=0, dp[0].rs=0; 29 for(int state=1;state<=ed_state;state++)//遍历状态 30 { 31 dp[state].rs=INF; 32 for(int co=n-1;co>=0;co--)//从后往前遍历课程 33 { 34 int k=1<<(n-1-co); 35 if(state & k)//如果当前状态,这门课作业已完成 36 { 37 int pre_state=state-k; 38 39 int tmp=dp[pre_state].time+course[co].cost-course[co].deadline; 40 if(tmp<0) tmp=0; 41 //算出要扣的分 42 if(tmp+dp[pre_state].rs < dp[state].rs) 43 { 44 dp[state].rs=tmp+dp[pre_state].rs; 45 dp[state].time=dp[pre_state].time+course[co].cost; 46 47 dp[state].now=co; 48 dp[state].pre=pre_state; 49 } 50 } 51 } 52 } 53 printf("%d\n",dp[ed_state].rs); 54 stack<int> output; 55 for(int i=ed_state;i!=0;i=dp[i].pre) output.push(dp[i].now); 56 while(!output.empty()) 57 { 58 cout<<course[output.top()].name<<endl; 59 output.pop(); 60 } 61 } 62 }
HDU 1074 - Doing Homework - [状压DP]
标签:images amp back input home alpha 题意 namespace ace
原文地址:http://www.cnblogs.com/dilthey/p/7594497.html