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;
}