Doing Homework-状压DP

本文详细解析了HDU-1074问题的动态规划解决方案,通过枚举所有作业完成状态,从初始状态到末状态进行遍历,使用dp数组记录每个状态下的最小罚时,最终输出最优作业完成顺序。

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

  • Doing Homework

  •  HDU - 1074 
  • 枚举所有 作业完成状态
  • 初始状态0末状态(1<<n)-1
  • 第一层i枚举各种状态
  • 第二层j查找当前i状态下第一个没完成的作业
  • 然后k循环查找一下当前完成的作业把时间记录求和来 判断  找到的这个未完成的作业 到底是怎么罚时的
  • dp更新i当前状态和把j位置完成的状态,并且更新前缀数组来记录罚时最少的排列方式。。
  • 最终所有状态 会枚举更新完成 输出时,因为 pre 数组记录的是 那个状态的十进制数字
  • 而我们需要输出那个状态下完成的哪一门作业,所以 二进制判断 cur当前的状态与pre[cur]状态的区别
  • 就知道这一步操作是完成的谁
  • PS:二进制操作如果优先级不熟悉老老实实的加括号
  • #include<iostream>
    #include<cstring>
    using namespace std;
    #define maxn 100
    #define inf 0x3f3f3f3f
    int n,t,dp[1<<20];
    int pre[1<<20],cnt;
    struct node
    {
        string name;
        int last,sum;
    } work[maxn];
    void print(int cur)
    {
        if(cur==0)
            return ;
        int order=0;
        for(int i=0; i<n; i++)
        {
            if((cur&(1<<i))!=0&&(pre[cur]&(1<<i))==0)
            {
                order=i;
                break;
            }
        }
        print(pre[cur]);
        cout<<work[order].name<<endl;
    }
    int main()
    {
        cin>>t;
        while(t--)
        {
            cin>>n;
            for(int i=0; i<n; i++)
                cin>>work[i].name>>work[i].last>>work[i].sum;
            memset(dp,inf,sizeof(dp));
            dp[0]=0;
            for(int i=0; i<(1<<n); i++)
            {
                for(int j=0; j<n; j++)
                {
                    if(i&(1<<j))
                        continue;
                    cnt=0;
                    for(int k=0; k<n; k++)
                        if(i&(1<<k))
                            cnt+=work[k].sum;
                    cnt+=work[j].sum;
                    if(cnt>work[j].last)
                        cnt-=work[j].last;
                    else
                        cnt=0;
                    if(dp[i|(1<<j)]>dp[i]+cnt)
                    {
                        dp[i|(1<<j)]=dp[i]+cnt;
                        pre[i|(1<<j)]=i;
                    }
                }
            }
            cout<<dp[(1<<n)-1]<<endl;
            print((1<<n)-1);
        }
        return 0;
    }
  •  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值