HDU 1074 Doing Homework (dp+状态压缩)

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

题目大意:学生要完成各科作业, 给出各科老师给出交作业的期限和学生完成该科所需时间, 如果逾期一天则扣掉一单位学分, 要你求出完成所有作业而被扣最小的学分, 并将完成作业的顺序输出.

Sample Input
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3
 
Sample Output
2
Computer
Math
English
3
Computer
English
Math

分析:(转)

刚开始以为是背包, 但背包难以记录输出顺序, 所以只能换另一种DP方式, 这里科目最大数目才15, 只要有全枚举的思想来DP就可以解决了, 有一个专有名词叫状态压缩DP. 状态压缩DP采用二制进的思想,

      1, 0分别代表有或否.

    如:

    3的二进制为 11, 则代表完成了每一,二个科目的状态, 101代表完成了第一三两个科目的状态.

    这样, 可以从0->(1 << N)来获取所有状态, 并进行适当的状态转移. 对该题来说 D[s]代表集合s的状态,  要得到D[s]的状态, 可以从0 - N 分别检查是否在s集合内[s & (1 << i) > 0则表示i在集合s上,反之..], 如果i在s集合内, 刚D[s]可从D[s-{i}]来获得, [s-{i},可以s - (1<<i)来计算]. 这样表示在已完成了s-{i}的基础上再完成i后的装态, 遍历i, 取最优解.

代码如下:

 1 # include<iostream>
 2 # include<cstdio>
 3 # include<string>
 4 # include<cstring>
 5 # include<stack>
 6 using namespace std;
 7 const int MAXN = 16;
 8 const int INF = 0xffffff;
 9 struct Homework{
10     string name;
11     int deadline;    //截止时间
12     int time;    //完成时间
13 }data[MAXN];
14 
15 struct {
16     int time;    //完成该集合作业所需时间
17     int score;    //完成该集合作业被扣学分
18     int last;    //记录上一个位置
19     int pos;    //记录当前位置
20 }dp[1<<MAXN];    
21 
22 int main(){
23     int T,n;
24     int i;
25     cin>>T;
26     while(T--){
27         cin>>n;
28         for(i=0;i<n;i++)
29             cin>>data[i].name>>data[i].deadline>>data[i].time;
30         int endstate = 1<<n;
31         int recent = 0;
32         int reduce = 0;
33         int past = 0;
34         for(int S=1; S<endstate; S++){
35             dp[S].score  = INF;
36 
37             for(i=n-1;i>=0;i--){
38                 recent = 1<<i;
39                 if(S & recent){
40                     past = S - recent;    //余下的作业集合
41                     reduce = dp[past].time + data[i].time - data[i].deadline;    //完成该作业被扣学分,小于0则不扣
42                     if(reduce < 0)
43                         reduce = 0;
44                     if(reduce + dp[past].score < dp[S].score){
45                         dp[S].time = dp[past].time + data[i].time;
46                         dp[S].score = reduce + dp[past].score;
47                         dp[S].pos = i;
48                         dp[S].last = past;
49                         
50                     }
51                 }
52             }
53         }
54         stack<int >path;    //保存路径
55         recent = endstate - 1;    //1<<n-1,表示n个1的2进制数,即全集
56         while(recent){
57             path.push(dp[recent].pos);
58             recent = dp[recent].last;
59         }
60         cout << dp[endstate-1].score<<endl;
61         while(!path.empty()){
62             int top = path.top();
63             cout<<data[top].name<<endl;
64             path.pop();
65         }
66     }
67     return 0;
68 }
原文地址:https://www.cnblogs.com/acm-bingzi/p/3278900.html