• HDU 1074 Doing Homework 状态压缩dp


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

    题目是给定n个科目(n <= 15)然后每个科目有最迟完成时间和需要多少天去完成。

    现在要你安排一个顺序去做这些科目,使得扣分最小,要求输出字典序最小的解。

    考虑用dp[i]表示完成了i的二进制那些科目时,所需的最小扣分。比如i(1001)就是完成了第1科和第四科。

    那么枚举这样的每一个状态,再枚举每一个科目,如果当前这个状态还没有完成这个科目的话,就是(i & (1 << j)) == 0的话。

    就可以进行转移了。可以用dp记录很多信息,包括当前状态的前一个状态(用于记录路径)和当前状态是选了哪一个科目(每一个新状态完成一个科目)和完成了当前状态的那些科目后,所需的最小扣分。和完成了当前状态的那些科目后,用了多少时间(这个用来记录后面枚举新科目的时候,是否会扣分)

    其实你想维护什么,dp那里都可以记录。关键是转移的时候要按照扣分的多少来转移就是了。

    如果从10001枚举到10011所需的扣分比从10010枚举到10011所需的最小扣分要小,


    那么就要更新了,但是反过来,如果是相等呢?

    相等的话,是不用变的,

    因为答案需要的是最小字典序解

    从10001枚举到10011

    就是先做1和5,再做4

    从10010枚举到10011

    就是先做1和4,再做5

    他们的cost相同,但是明显下面的字典序比较小(因为题目已经排好序)

    所以,是不用变了

    最后,dp数组要开到 1 << 15

    一开始开了15,一直TLE

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    struct nodeInformation {
        char name[100 + 20];
        int dead;
        int need;
    }a[15 + 20];
    struct nodeDp {
        int pre;
        int cur; //当前这个是什么
    
        int cost; //记录扣多少分
        int tim; //什么时候完成了这个状态
    }dp[1 << 16];
    void show(int val) {
        if (val == 0) return;
        show(dp[val].pre);
        printf("%s
    ", a[dp[val].cur].name);
    }
    void work() {
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; ++i) {
            scanf("%s%d%d", a[i].name, &a[i].dead, &a[i].need);
        }
        int end = 1 << n;
        memset(dp, 0x3f, sizeof dp);
        dp[0].cost = 0;
        dp[0].pre = -inf;
        dp[0].tim = 0; //一科都没完成的状态
        dp[0].cur = -inf;
        for (int i = 0; i < end; ++i) { //枚举每一个状态
            for (int j = 0; j < n; ++j) {
                if ((i & (1 << j)) == 0) { //如果没完成到这个科目,才能转移
                    int newState = i | (1 << j);
                    int dayTofinish = dp[i].tim + a[j].need;
                    int cost = dayTofinish - a[j].dead;
                    if (cost < 0) cost = 0; //就是提前完成了,不用扣费
                    cost += dp[i].cost;
    
                    if (cost < dp[newState].cost) { //现在这样花费比以前的小
                        dp[newState].cost = cost;
                        dp[newState].cur = j;
                        dp[newState].pre = i; //i这个状态
                        dp[newState].tim = dayTofinish;
                    }
                }
            }
        }
        printf("%d
    ", dp[end - 1].cost);
        show(end - 1);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code
  • 相关阅读:
    请求的详细资料级别没有事实表
    BIEE汇总数据如何放在后面
    Biee仪表盘中提示空值如何去掉
    UFT测试本地应用程序登陆小实例(描述性编程)
    Mysql找回丢失密码
    linux下Mysql多实例实现
    如何从零安装Mysql
    Linux系统下yum源配置(Centos 6)
    Linux系统管理常用命令用法总结(2)
    Linux系统管理常用命令用法总结(1)
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5999414.html
Copyright © 2020-2023  润新知