hdu 1074 doing homework

24 篇文章 0 订阅
1 篇文章 0 订阅

状态压缩dp
首先进行状态映射,(状态压缩),一共有15门课,每门课则可用一个数字位 来表示这门课作业是否已经做完,比如3门课 001,表示完成了第一门课作业,101,表示完成了第1门,第 3门作业。 则需要一个0-15位整数范围的数来表示所有状态
初始状态000, 结束状态1111…11 表示完成了所有作业。
再找状态转移方程
对于状态i, 这个状态可能由前一个状态pre,加上做完一道作业j得到。
也就是说对于所有状态i,和作业j,如果(i &1<<j) ==0 则表示状态i包含了完成了作业j, 通过 i^(1<<j) 来得到前一个状态pre
状态转移方程:

dp[i]= min{dp[pre]+cost[j]} //pre is a set

由于需要记录完成顺序,且按字典序小的输出,开一个数组,pre[i]
来表示到达,i状态的需要完成的作业j
所以需要反向循环作业j,以此来保证字典序小的优先

核心代码

for(int i=1;i<m;i++{
    for(int j=n-1;j>=0;j--)
    {
        int tmp=1<<j;
        if(!(i&tmp)) continue;
        int pre=i^tmp;
        if(dp[pre]+cost[j]<dp[i]){
            //update dp[i]
            dp[i]   =dp[pre]+cost[j];
            Pre[i]=j; // the Pre is the array that for record;
        }
    }
}

下面是几个参考博客:

http://www.cnblogs.com/neopenx/p/4048722.html

http://blog.csdn.net/acvay/article/details/48051975

下面是ac代码:

#include <iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

#define MAX 105
#define INF  1000000
typedef struct Node{

    char name[MAX];

    int cost;
    int deadline;
}Lesson;


Lesson homework[20];

#define  mx 1<<15


int dp[mx];
int p[mx];
int ti[mx];


void showTrace(int n){

    if(p[n]==-1)return;

    showTrace(n^(1<<p[n]));
    cout<<homework[p[n]].name<<endl;
}
int main()
{

   int t;
   scanf("%d",&t);

   int n=0;
   while(t--){
    scanf("%d",&n);
    for(int i=0;i<n;i++){

        scanf("%s%d%d",homework[i].name,
              &homework[i].deadline,&homework[i].cost);
    }
    memset(dp,1000000,sizeof(dp));
    memset(p,-1,sizeof(p));
    dp[0]=0;
    p[0]=-1;
    ti[0]=0;
    int m=1<<n;
    for(int i=1;i<m;i++){

        for(int j=n-1;j>=0;j--){

            int tmp=(1<<j);
            //whether is the i contains j
            if((i&tmp)==0) continue;
            // get the pre status which add j is i
            int pre=i^tmp;

            //pre is the status before j,
            // the i is the status contains j
            int reduce=ti[pre]+homework[j].cost-homework[j].deadline;

            reduce=reduce<0?0:reduce;


            // the status change function
            // dp[i]= min{dp[pre]+ cost[j]}
            // where pre is the status which add j is i
            if(dp[pre]+reduce<dp[i]){

                dp[i]=dp[pre]+reduce;
                p[i]=j;
                ti[i]=ti[pre]+homework[j].cost;
            }
        }
    }

    printf("%d\n",dp[m-1]);

    showTrace(m-1);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值