hdu 1074——Doing Homework

本文介绍了一种使用状态压缩动态规划方法解决作业规划问题的算法。该问题要求在考虑截止日期和作业所需时间的前提下,尽可能减少因延误而扣分的情况。通过状态压缩,将每个作业是否完成的状态用二进制数表示,并设计了动态规划方程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:每个作业有最后期限和写这个作业要花费的时间。每超过最后期限一个单位时间就会减掉一分。求最少减掉多少分。
思路:状态压缩。最多15个科目。最多就15位就够了。
当这一位是1的时候就表示这个作业已经完成了。全1代表全部完成。动态规划方程:
dp(sta)=min{ dp(from) + (timeused(sta) - deadline(i) ) }
其中dp(sta)代表了在i状态的时候,最少减去的分数。timeused(sta)代表了状态i的时候,需要花费的时间。deadline(i)代表了第i门作业的最后期限。from是能到达sta的状态。from应该是跟sta只有第i位不一样。
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int dp[1<<16];
char subject[19][105];
int pre[1<<16];
int dl[19];
int cost[19];
int ans[19];
int n;

inline int timeused(int sta){
    int ret=0;
    int tot=0;
    while(sta>0){
        if(sta&1){
            ret+=cost[tot];
        }
        tot++;
        sta>>=1;
    }
    return ret;
}

void getans(int sta){
    int tot=0;
    while(sta>=0){
        if(sta&1){
            printf("%s\n",subject[tot]);
            return;
        }
        tot++;
        sta>>=1;
    }
    return;
}

int dfs(int sta)
{
    if(dp[sta]>=0)return dp[sta];
    for(int bit=n-1;bit>=0;--bit){//从后往前保证字典序
        int sub=1<<bit;
        if(sta&sub){
            int from=sta^sub;
            int tu=timeused(from);
            int reduse=tu+cost[bit]-dl[bit];
            if(reduse<0)reduse =0;
            reduse+=dfs(from);
            if(dp[sta]>reduse||dp[sta]==-1){
                dp[sta]=reduse;
                pre[sta]=from;
            }
        }
    }
    return dp[sta];
}

int main()
{
//    freopen("data.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<n;++i){
            scanf("%s",subject[i]);
            scanf("%d%d",&dl[i],&cost[i]);
        }
        int last=(1<<n)-1;
        dp[0]=0;
        dfs(last);
        printf("%d\n",dp[(1<<n)-1]);
        int cnt=0;
        for(int i=last;i>0;){
            ans[cnt++]=i^pre[i];
            i=pre[i];
        }
        for(int i=n-1;i>=0;--i){
            getans(ans[i]);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值