HDU 1074 Doing Homework DP 状压DP

  题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074

  题目描述: 给你所有课程的截止时间和工作时长, 一次只能做一种作业, 问最少罚时几天 N <= 15

  解题思路: 由于N很小, 所以第一反应就是状压DP, 我们可以用一个15位二进制数来表示各个课程做完还是没做完, 然后从 S 从 1 到 1 << N 枚举 i 从 1 到 N 枚举, 如果S & (1<<i) 有效则说明i 属于情况 S, 这样我们从上一步S - 1 << i 转移过来就可以, 记录路径就是每当出现答案的更新就将此时的状态和当前处理的位数记住, 压入栈中, 最后再倒着打出来

  代码: 

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <cstring>
#include <iterator>
#include <cmath>
#include <algorithm>
#include <stack>
#include <deque>
#include <set>
#include <iterator>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;

const int maxn = 20;
int deadline[maxn];
int cost[maxn];
string name[maxn];
const int INF = 0x3fffffff;
set<string> ans;
struct node {
    int time, score, pre, now;
};
node dp[1<<15];
set<string>::iterator it;

int main() {
    int t;
    cin >> t;
    while( t-- ) {
        ans.clear();
        memset(dp, 0, sizeof(dp));
        int n;
        cin >> n;
        for( int i = 0; i < n; i++ ) {
            cin >> name[i] >> deadline[i] >> cost[i];
        }
        int end = 1 << (n);
//        cout << end << endl;
        for( int s = 1; s < end; s++ ) {
            dp[s].score = INF;
            for( int i = n-1; i >= 0; i-- ) {
                int temp = 1 << i;
                if( temp & s ) {
                    int past = s- temp;
                    int st = dp[past].time + cost[i] - deadline[i];
                    if( st < 0 ) st = 0;
                    if( st + dp[past].score <  dp[s].score ) {
                        dp[s].score = st + dp[past].score;
                        dp[s].pre = past;
                        dp[s].now = i;
                        dp[s].time = dp[past].time + cost[i];
                    }
                }
            }
        }

        stack<int> S;
        int tem = end-1;
        cout << dp[tem].score << endl;
        while(tem)
        {
            S.push(dp[tem].now);
            tem = dp[tem].pre;
        }
        while(!S.empty())
        {
            cout << name[S.top()] << endl;
            S.pop();
        }
    }
    return 0;
}

  思考: 自己一开始只知道是状压DP, 具体该怎么做还是不知道, 要接触各种DP

时间: 2024-11-01 22:41:25

HDU 1074 Doing Homework DP 状压DP的相关文章

HDU 1074 Doing Homework (状压dp)

题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则按照作业字典序输出(注意:输入也是按照字典序输入的) 题解:首先想到的是暴力dfs,但是会超时.接着我们看到n最大只有15,因此可以使用状压dp,但是状态不能用位置表示 但我们可以这样:0表示此作业没有做过,1表示已经用过了,接着遍历0->(1<<n)-1贪心(例如:3(011)可以找2(0

HDU 1074 Doing Homework(状压dp)

Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6299    Accepted Submission(s): 2708 Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a l

hdu 1074 Doing Homework(状压)

题意:有n个作业,有截止日期和需要完成的时间,超出期限一天就扣一分.问最少扣多少分 思路:因为最多15门课,而15!太大了,所以进行状压,而2^15只有3w多,所以是可以进行的,状压后,把每种情况都枚举一下,然后同时进行时间和分数的dp,最后把分数都转移到bit-1,虽然我懂了是怎样状压dp的,但我不知道是怎么打印出来的,只知道是类似于用并查集维护一样,我打印了并查集数据也没看出来,还是不行呐 代码: #include <bits/stdc++.h> using namespace std;

HDU 4114 Disney&#39;s FastPass (状压DP)

题意:给定 n 个区域,然后给定两个区域经过的时间,然后你有 k 个景点,然后给定个每个景点的区域和有票没票的等待时间,从哪些区域能够得到票,问你从景点1开始,最后到景点1,而且要经过看完这k个景点. 析:一个状压DP,dp[s1][s2][i] 表示已经访问了 s1 中的景点,拥有 s2 的票,当前在 i 区域,然后两种转移一种是去下一个景点,另一种是去下一个区域拿票.当时输入,写错了,卡了好长时间.... 代码如下: #pragma comment(linker, "/STACK:10240

POJ 2411 &amp;&amp; HDU 1400 Mondriaan&#39;s Dream (状压dp 经典题)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12341   Accepted: 7204 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

HDU 4906 Our happy ending (状压DP)

HDU 4906 Our happy ending 题目链接 题意:给定n个数字,每个数字可以是0-l,要选其中一些数字,然后使得和为k,问方案 思路:状压dp,滚动数组,状态表示第i个数字,能组成的数字状态为s的状态,然后每次一个数字,循环枚举它要选取1 - min(l,k)的多少,然后进行状态转移 代码: #include <cstdio> #include <cstring> typedef long long ll; const int N = (1<<20)

HDU 4856 Tunnels(BFS+状压DP)

HDU 4856 Tunnels 题目链接 题意:给定一些管道,然后管道之间走是不用时间的,陆地上有障碍,陆地上走一步花费时间1,求遍历所有管道需要的最短时间,每个管道只能走一次 思路:先BFS预处理出两两管道的距离,然后状态压缩DP求解,dp[s][i]表示状态s,停在管道i时候的最小花费 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using

2017.8.15 [Haoi2016]字符合并 区间dp+状压dp

[题目描述] 有一个长度为n的01串,你可以每次将相邻的k个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这k个字符确定.你需要求出你能获得的最大分数. [输入格式] 第一行两个整数n,k. 接下来一行长度为n的01串,表示初始串.输入的的相邻字符之间用一个空格隔开. 接下来2k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符, wi表示对应的第i种方案对应获得的分数. [输出格式] 输出一个整数表示答案. [

『字符合并 区间dp 状压dp』

字符合并 Description 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这 k 个字符确定.你需要求出你能获得的最大分数. Input Format 第一行两个整数n,k.接下来一行长度为n的01串,表示初始串. 接下来2^k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符,wi表示对应的第i种方案对应获得的分数. 1<=n<=300,0<

HDU 1074:Doing Homework(状压DP)

http://acm.hdu.edu.cn/showproblem.php?pid=1074 Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7704    Accepted Submission(s): 3484 Problem Description Ignatius has just come bac