HDU 1074 Doing Homework【状态压缩DP】

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1074

题意:

给定作业截止时间和完成作业所需时间,比截止时间晚一天扣一分,问如何安排作业的顺序使得最终扣分最少?

分析:

最多只有15节课,可以将完成作业的情况进行状态压缩,用二进制表示,枚举出状态,进行dp。
然后注意输入的时候本身就是字典序最小的,倒着来一遍,先不写后面的作业,这样最终得到的答案就是按字典序小的排列的了。
dp最初忘记1<<maxn,悲哀的TLE了两发。。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define sa(a) scanf("%d", &a)
#define sal(a) scanf("%I64d", &a)
const int maxn = 15 + 5, INF = 0x3f3f3f3f;
struct hwk{char s[105]; int d;int c;};
hwk p[maxn];
struct DP{int day; int pre; int v;};
DP dp[1<<maxn];
int n;
void print(int st)
{
    if(!st) return;
    print(dp[st].pre);
    int now = dp[st].pre^st;
    int res;
    for(int i = 0; i < n; i++){
        if(now >> i & 1) {res = i;break;}
    }
    printf("%s
", p[res].s);
}
int main (void)
{
    int T;sa(T);
    while(T--){
        sa(n);
        for(int i = 0; i < (1<<n); i++){
            dp[i].day = 0;
            dp[i].pre = 0;
            dp[i].v = INF;
        }
        dp[0].v = 0;
        for(int i = 0; i < n; i++){
            scanf("%s", p[i].s);
            sa(p[i].d); sa(p[i].c);
        }
        int en = 1 << n;
        for(int i = 1; i < en; i++){
             for(int j = n - 1; j >= 0; j--){
                 if(i>>j & 1){
                    int be = i - (1 << j);
                    int tmp = dp[be].day + p[j].c - p[j].d;
                    if(tmp < 0) tmp = 0;
                    if(tmp + dp[be].v < dp[i].v){
                        dp[i].v = tmp + dp[be].v;
                        dp[i].pre = be;
                        dp[i].day = dp[be].day + p[j].c;
                    }
                 }
             }
        }
        printf("%d
", dp[en - 1].v);
        print(en -1);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758678.html