Doing Homework
题目链接:HDU - 1074题意:有n科作业需要做, 给出每科作业的名字, 上交时间(最晚完成期限), 完成作业需要的时间;当作业完成时已超过最晚期限, 则每超一天扣一分;让你合理安排时间, 使得扣分最少, 然后输出路径, 如果有多个答案输出字典序最小的;
n的范围是1~15, 一共n!种情况, 扫一遍所有情况明显不靠谱, 想到了状压DP, dp[i]表示状态扣的分, path[i]表示i状态是作path[i]得到的(这就是路径, 最后递归输出),time[i]表示状态已经用了time[i]时间;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=35000;
const int INF=0x3f3f3f3f;
int N;
char s[20][150];
int d[20], t[20];
int dp[maxn], path[maxn], time[maxn];
void print(int x){
if(x==0) return;
print(x-(1<<(path[x]-1)));
printf("%s\n", s[path[x]]);
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d", &N);
for(int i=1; i<=N; i++){
scanf("%s%d%d", s[i], &d[i], &t[i]);
}
memset(time, 0, sizeof(time));
for(int i=1; i<(1<<N); i++){
dp[i]=INF;
for(int j=N; j>0; j--){//题目要求字典序最小;
if((i&(1<<(j-1)))==0) continue;
int score=time[i-(1<<(j-1))]+t[j]-d[j];
if(score<=0) score=0;
if(dp[i]>dp[i-(1<<(j-1))]+score){//因为for循环是N~1,所以这里没有等号,保证字典序最小,若循环变为1~N,这里加上等号;
dp[i]=dp[i-(1<<(j-1))]+score;
time[i]=time[i-(1<<(j-1))]+t[j];
path[i]=j;
}
}
}
printf("%d\n", dp[(1<<N)-1]);
print((1<<N)-1);
}
return 0;
}