• HDU-1074.DoingHomework(撞鸭dp二进制压缩版)


    之前做过一道二进制压缩的题目,感觉也不是很难吧,但是由于见少识窄,这道题一看就知道是撞鸭dp,却总是无从下手....最后看了一眼博客,才顿悟,本次做这道题的作用知识让自己更多的认识二进制压缩,并无其它卵用......呜呜呜~~~

      本题大意:到期末了,某同学的n位老师给他布置了n门家庭作业,要求他在布置作业后的D天之内完成,并且已知它每门作业所需的天数C,每门作业超时一天就要扣一分,让你求出要如何合理安排做作业的顺序才能使他扣掉的总分最少......还需要输出做作业的顺序和最优情况下扣的分数......

      本题思路:因为要得到所有做题的顺序就有n!种这么多,那么此时我们看到n  <= 15,那就能考虑到二进制撞鸭了,二进制撞鸭之前发过一个博客有讲过,这里再强调一下比如0101表示第1和3科的作业做了,第二科作业没做,那么我们可以枚举做作业先后的所有的情况,然后取最优即可,这只是思路,那么具体我们要如何分析这个问题呢

    下面我详细讲解......

      首先思考一个问题:我们二进制枚举所有的写作先后过程,那么我们的dp要保存什么状态呢,第一我们需要先找出最小分数即score,需要回溯保存一个过程的上一个过程pre,需要每次写作业之后更新已经过去的时间time,需要保存当前正在写作业的下标ind,就ok了,对于dp[ i ],我们在所有科目中逆序寻找(为什么是逆序寻找呢....因为我们需要利用一个数组存做作业的先后顺序,也就是利用一个pre存它之前完成的状态的编号,遍历输出时顺序也是反的,为了保证字典序输出,我们只能逆着遍历,~~~~(>_<)~~~~呜呜呜~~~),如果发现i状态下如果已经完成了作业j,那么我们就将作业j分离出来在这一步单独再次完成,在这一步利用dp[i - 1<<j]将dp[ i ]的值更新并找到最小值(由于在完成三项任务1, 2, 3时肯定要完成对应的前两项1,2 || 2,3 || 1,3),那么我们的最优值就是由这个思路得来的,由于i - 1<<j 恒小于i,所以它在i之前求得,我们就可以对dp[ i ]的值进行更新,那么对于dp[ i ],我们就可以写出他的状态转移方程dp[ i ] = max(dp(i - 1 << j) + dp[ j ])(j 为状态i 的一个子问题)。

      参考代码:

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <stack>
     5 using namespace std;
     6 
     7 const int maxn = 15 + 2, INF = 0x3f3f3f3f;
     8 int t, n;
     9 struct node {
    10     string name;
    11     int deadline, cost;
    12 } a[maxn];
    13 struct node1 {
    14     int pre, time, score, ind;
    15 } dp[1 << 15];
    16 
    17 int main () {
    18     ios::sync_with_stdio(false);
    19     cin >> t;
    20     while(t --) {
    21         cin >> n;
    22         for(int i = 0; i < n; i ++)
    23             cin >> a[i].name >> a[i].deadline >> a[i].cost;
    24         memset(dp, 0, sizeof dp);
    25         int nbit = 1 << n;
    26         for(int i = 1; i < nbit; i ++) {
    27             dp[i].score = INF;
    28             for(int j = n - 1; j >= 0; j --) {
    29                 int temp = 1 << j;
    30                 if(!(temp & i)) continue;
    31                 int tem = i - temp;
    32                 int t = dp[tem].time + a[j].cost - a[j].deadline;
    33                 t = t > 0 ? t : 0;
    34                 if(t + dp[tem].score < dp[i].score) {
    35                     dp[i].score = t + dp[tem].score;
    36                     dp[i].pre = tem;
    37                     dp[i].ind = j;
    38                     dp[i].time = dp[tem].time + a[j].cost;
    39                 }
    40             }
    41         }
    42         cout << dp[nbit - 1].score << endl;
    43         stack<int> q;
    44         int t = nbit - 1;
    45         while(dp[t].time) {
    46             q.push(dp[t].ind);
    47             t = dp[t].pre;
    48         }
    49         while(!q.empty()) {
    50             int k = q.top();
    51             cout << a[k].name << endl;
    52             q.pop();
    53         }
    54     }    
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    在网页上下载文件
    sql server 分离附加
    在vue中,ref属性与$refs对象的区别
    在ES6中,export default 和 export的区别
    element-ui之Table表格el-table标签
    element-ui之Form表单el-form标签
    使用Mybatis-Generator自动生成Dao,Entity,Mapping
    linux下普通用户与root的切换
    idea插件将下划线转驼峰形式
    利用wsdl2java工具生成webservice的客户端代码
  • 原文地址:https://www.cnblogs.com/bianjunting/p/10627380.html
Copyright © 2020-2023  润新知