HDU-1074-Doing Homework
http://acm.hdu.edu.cn/showproblem.php?pid=1074
状态压缩DP,我们可以使用一个二进制的数来表示做作业的状态,1表示做了,0表示没做
dp[i]表示状态i损失的分数,再做一个作业x可到另一状态dp[j],则要有i&x==0,若要有dp[a],dp[b]均可以到达dp[j],那么选择损失分数最小的,若分数相同,按题意的字典序,即选择a和b中较小的一个,因为题目的课程是按字典序给出的。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> using namespace std; const int Max=1<<16; struct node { int time; //该状态的时间 int pre; //前一状态 int cost; //最小的损失 }dp[Max]; struct course { int deadtime; //截止日期 int cost; //所需时间 char name[201]; }course[16]; int visit[Max]; void print(int status) { int cur,num; cur=dp[status].pre^status; //刚做的课程 num=0; cur>>=1; while(cur) { num++; cur>>=1; } if(dp[status].pre!=0) print(dp[status].pre); printf("%s\n",course[num].name); } int main() { int i,n,t; int upper,work,cur,k,reduce; scanf("%d",&t); while(t--) { scanf("%d",&n); upper=(1<<n)-1;//最大的状态 for(i=0;i<n;i++) scanf("%s%d%d",&course[i].name,&course[i].deadtime,&course[i].cost); memset(visit,0,sizeof(visit)); dp[0].time=0; //初始化 dp[0].pre=-1; dp[0].cost=0; visit[0]=1; for(i=0;i<upper;i++) { for(work=0;work<n;work++) { cur=1<<work; if((cur&i)==0) //该项课程还未做 { k=cur|i;//下一状态 dp[k].time=dp[i].time+course[work].cost; reduce=dp[k].time-course[work].deadtime; if(reduce<0) reduce=0; reduce+=dp[i].cost; if(visit[k]) //该状态已标记 { if(reduce<dp[k].cost) { dp[k].cost=reduce; dp[k].pre=i; } else if(reduce==dp[k].cost) { if(dp[k].pre>i) dp[k].pre=i; } } else { visit[k]=1; dp[k].cost=reduce; dp[k].pre=i; } } } } printf("%d\n",dp[upper].cost); print(upper);//递归输出 } return 0; }