HDU1074(状压DP)

题目链接

题意:有n门课,每门课都要交作业,作业有时间花费和最晚提交日期,如果超过日期交作业,每超过一天就要扣一分,问最少扣多少分并且给出最少扣分的方案。

题解:
因为最多只有15门课,所以可以压缩成一个数,二进制位上每一位代表一门课是否完成。然后开始DP。
枚举从1到1<< n的每一个状态i,然后枚举每一门课j(倒叙枚举,因为输入是按照字典序递增输入的),检查状态i是否完成了第j门课(可以通过与运算完成),如果完成了第j门课,计算不完成第j门课时所扣的分加上完成第j门课所扣的分是否比当前状态i所扣的分少,如果少于则进行更新分数和时间,并记下j作为路径输出。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = (1 << 15) + 10;
const int inf = 99999999 ;
int dp[maxn],time[maxn],n,t,dead[20],cost[20],pre[maxn];
char s[20][105];
void solve()
{
    int maxm = 1 << n;
    for (int i = 1; i < maxm; i++)
    {
        dp[i] = inf;
        for (int j = n - 1; j >= 0; j--)
        {
            int temp = 1 << j;
            if(!(i & temp))continue;
            int score = time[i - temp] + cost[j] - dead[j];
            if(score < 0)score = 0;
            if(dp[i - temp] + score < dp[i])
            {
                dp[i] = dp[i - temp] + score;
                time[i] = time[i - temp] + cost[j];
                pre[i] = j;
            }
        }
    }
}
void print(int ans)
{
    if(!ans)return ;
    print(ans - (1<<pre[ans]));
    printf("%s\n",s[pre[ans]]);
}
int main()
{
    scanf("%d",&t);
    while (t--)
    {
        memset(s,0,sizeof s);
        memset(dead,0,sizeof dead);
        memset(cost,0,sizeof cost);
        memset(time,0,sizeof dp);
        memset(pre,0,sizeof pre);

        scanf("%d",&n);
        for (int i = 0; i < n; i++)
            scanf("%s %d %d", &s[i],&dead[i],&cost[i]);

        solve();

        int ans = (1 << n) - 1;
        printf("%d\n",dp[ans]);
        print(ans);

    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值