题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1074
题目大意:给你N 个任务,每行一个任务名称,一个该任务截止完成时间,一个完成该任务需要的时间,一个任务超时一天 惩罚加一,问所有任务完成的最小惩罚是多少?
解题思路:就是挑选一个最优做题顺序问题,但是要输出字典序最小的做题顺序,但是这道题 给的课程名称都是按字典序排列好的,因此只需要 按照字典序去递推即可,其中用pre[]记录每个状态是由 哪一个前状态递推来的,记录递推过来的那门课程,当递推到最后,只需要查找一下最优状态的pre[]值,输出来即可,同时要注意,当一个任务在规定时间之后完成,无论是否开始做该任务,该任务的惩罚都在加一,因此在递推过程中要一直更新当前状态总用时。
代码如下:
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
#define inf 0x3f3f3f3f
int n,cost[16],del[16],dp[1<<16],mark[1<<16];
char s[20][20];
int pre[1<<16],num;
void out(int x) //输出路径
{
if(x==0) return;
out(x-(1<<pre[x]));
printf("%s\n",s[pre[x]]);
}
void solve()
{
num=(1<<n);
mark[0]=0;
dp[0]=0;
for(int i=1;i<num;i++)
{
dp[i]=inf;
for(int j=n-1;j>=0;j--) //从n-1开始,即从第一个任务开始,即字典序最小
{
if(i&(1<<j))
{
int tmp=mark[i-(1<<j)]+cost[j]-del[j];//计算超时时间
if(tmp<0) tmp=0;
if(dp[i-(1<<j)]+tmp<dp[i])
{
dp[i]=dp[i-(1<<j)]+tmp;
mark[i]=mark[i-(1<<j)]+cost[j];//更新当前状态所有任务的花费总时间
pre[i]=j;//记录该状态的前驱
}
}
}
}
printf("%d\n",dp[num-1]);
out(num-1);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%s%d%d",s[i],&del[i],&cost[i]);
solve();
}
return 0;
}