HDU 1074 Doing Homework 经典DP

题目链接点我

题目大意是小明有很多功课要去做,都要做完,每门课有一个截止时间和做它需要的时间。

注意到数据量是15,这很明显告诉我们可以枚举用二进制
对,一开始我还真的没想出来状态是什么
看到数据量后,就以二进制为状态
比如7就表示第一门第二门第三门功课做完需要最小的时间

下面贴代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <iostream>
using namespace std;

const int inf = 0x3f3f3f3f;


struct po
{
    char name[101];
    int d,l;
};

po a[50];


struct node
{
    int pre,now,v,time;
};


node dp[(1<<16)];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        getchar();
        for(int i=0;i<n;i++){
            scanf("%s %d%d%*c",a[i].name,&a[i].d,&a[i].l);
            //printf("%s %d %d\n",a[i].name,a[i].d,a[i].l);
        }

        for(int i = 1;i<(1<<n);i++){ //枚举二进制状态
            dp[i].v = inf;
            for(int j=n-1;j>=0;j--){
                if((i>>j)&1){
                    int past = i-(1<<j);
                    int tt = dp[past].time + a[j].l - a[j].d;
                    if(tt<0) tt=0;
                    if(dp[past].v + tt < dp[i].v){
                        dp[i].v = dp[past].v + tt;
                        dp[i].time = dp[past].time + a[j].l;
                        dp[i].now = j;
                        dp[i].pre = past;
                    }

                }
            }
        }
        printf("%d\n",dp[(1<<n)-1].v);
        int tmp = (1<<n)-1; // 结果要倒过来输出
        stack<int> S;
        while(tmp){
            S.push(dp[tmp].now);
            tmp = dp[tmp].pre;
        }
        while(!S.empty()){
            int i = S.top();S.pop();
            printf("%s\n",a[i].name);
        }
    }
    return 0;

}

学dp的路还很长,坚持才能逐渐掌握。
毕竟这世界套路太深。

发布了40 篇原创文章 · 获赞 7 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章