HDU 1074 状态压缩DP 作业扣分

本文介绍了一种使用状态压缩动态规划(DP)的方法来解决作业调度问题,以最小化因延迟提交作业而造成的分数损失。通过具体示例,详细解释了如何编码状态并更新DP数组,最终确定最优的作业完成顺序。

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

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

Ignatius刚刚从第30届ACM / ICPC回到学校。 现在他做了很多功课。 每个老师给他一个交付作业的最后期限。 如果Ignatius在截止日期之后交作业,老师将减少他的最后考试成绩,1天1分。 正如你所知,做作业总是需要很长时间。 所以Ignatius希望你帮助他安排做作业的顺序,以减少分数。输出最少扣分的做作业顺序。

输入n,0<n<=15 例子数,课程名,截止日期,完成天数。

2 3 Computer 3 3 English 20 1 Math 3 2 3 Computer 3 3 English 6 3 Math 6 3
 

Sample Output
2 Computer Math English 3 Computer English Math

思路:这道题有一个明显的标志,N为15,一般N为15 16都是用状态压缩DP。所谓状态压缩DP就是采用二分的思想对应于每一种状态,然后对每种状态从小到大进行更新。n门课,(1<<n)-1,有n个1,表示n门课都完成。若该位为0,表示这门课没有完成。i从1到1<<n  -1,模拟所有情况。对每种情况d[i],假设有m门课完成,肯定是由m-1门状态而来,所以只要遍每门课没完成的的状态,找到最小值。然后+当前课程所扣的分数。

如何找到d[i]中完成的课程,可以用i&(1<<j)表示第j门是否在i中。找到最小值后,把它记录到路径当中。print[i],记录i状态时,最新完成的作业。最终打印的时候可以回溯,先从x=1<<n   -1的情况开始,放到最后输出,然后x-1<<print[x],表示之前的情况,输出。直到x为0.

#include<stdio.h>
#include<iostream>
using namespace std;
const int maxn=(1 << 15) + 10;
#define INF  (1 << 31) - 1;
int dp[maxn], print[maxn], time[maxn];
struct
{
    char name[110];
    int ddl, actual;
} a[20];
void output(int x)
{
    if (!x)return;
     output(x - (1 << print[x]));
     printf("%s\n", a[print[x]].name);
}
int main()
{
    int T,n,i;
    cin >> T;
    while (T--)
    {
        cin >> n;
        for (i = 0; i < n; i++)
            cin >> a[i].name >> a[i].ddl >> a[i].actual;
        int total = 1 << n;
        for (i = 1; i < total; i++)//n门做完,1<<n-1都是1
        {
            dp[i] = INF;
            for (int j = n - 1; j >= 0; j--)     //因为按照字母序,i-temp要从小到大,temp从大到小
            {
                int temp = 1 << j;//表示第J门是否做    
                if (!(i&temp))continue;//如果状况iz中第j门不做,跳过
                int score = time[i - temp] + a[j].actual - a[j].ddl;
                if (score < 0)score = 0;//证明截止时间前就完成了
                if (dp[i] > dp[i - temp] + score)//更新状态i的最小值
                {
                    dp[i] = dp[i - temp] + score;
                    time[i] = time[i - temp] + a[j].actual;//记录i情况下的时间
                    print[i] = j;
                }
            }
        }
        cout << dp[total - 1] << endl;
        output(total - 1);
    }

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值