(1074)HDU-状态压缩

http://blog.csdn.net/libin56842/article/details/24316493


http://blog.csdn.net/xingyeyongheng/article/details/21742341#comments


首先贴两个状态压缩的题解,这是第一个状态压缩DP,想了一下午,不知道是不是有点慢····


然后在贴下我自己的代码

#include<iostream>
#include<cstdio>
#include<string.h>
#include<string>
#include<set>
#include<algorithm>
#include<cmath>
#include<stack>


#define ll __int64
#define MAX 1000009
using namespace std;
/*
题意:给你n门功课,每门功课的截止时间和需要完成的天数,没超过截止时间一天,失去分数+1,问你如何排列做作业顺序的情况下,失去分数最小
分析:一共有n!情况,假设 n = 3的时候1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1 这些完成他们消耗的天数是一定的,只是完成顺序不同,所以扣得分数
也是不一样,这样我们就发现了状态,我们把完成相同的作业数看成一种状态,在该状态下,只是功课排列顺序不同,我们求出扣分最小的那一组
这样,我们就来写下状态压缩DP


dp[s] 表示 s状态下失去的最小分数


我们只需要枚举所有作业的情况就可以把状态求出来
我们怎么表示每个作业的完成情况呢?
二进制!位运算
例如 5 101 代表第一,第三门功课完成


假设功课k,状态i 我们怎么得出dp[i]呢,dp[i]由未完成k的dp[i]推出完成K的dp[i]
状态j = i-(1<<k)来完成k达到,并且j<i,如果从0-2^1那么j一定先算过
*/


struct node
{
    string name;//名称
    int endd;//截止时间
    int use;//消耗时间
} a[50];


struct kode
{
    int time;//时间
    int score;//分数
    int pre;//前驱
    int now;//当前节点
} dp[MAX];


int main()
{
    int T;
    int n;
    int i,j;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(i = 0; i<n; i++)
            cin>>a[i].name>>a[i].endd>>a[i].use;
        int bit = 1<<n;
        for(i = 1; i<bit; i++) //枚举状态
        {
            dp[i].score = MAX;//初始化


            for(j = n-1; j>=0; j--)
            {
                int temp = 1<<j;
                if(i&temp)//状态i不存在作业j完成则不能通过完成作业j到达状态i
                {
                    int past = i - temp;
                    int st = dp[past].time + a[j].use - a[j].endd;//i-temp表示没有完成j的那个状态
                    if(st<0)
                        st = 0;//完成j被扣分数最小是0
                    if(dp[i].score>dp[past].score + st)
                    {
                        dp[i].score = dp[past].score + st;//当前状态下被扣的分数
                        dp[i].now = j;//当前节点
                        dp[i].pre = past;//到达状态i的前驱,为了最后输出完成作业的顺序
                        dp[i].time = dp[past].time + a[j].use;//到达状态i花费的时间
                    }
                }
            }
        }
        stack<int>S;
        int tem = bit - 1;
        cout<<dp[tem].score<<endl;
        while(tem)//这里不断找前驱节点然后存进stack里
        {
            S.push(dp[tem].now);
            tem = dp[tem].pre;
        }
        while(!S.empty())
        {
            cout<<a[S.top()].name<<endl;
            S.pop();
        }


    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值