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