hdu1074 状态压缩dp

                                                                              Doing Homework

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4685    Accepted Submission(s): 1917


Problem Description
Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will reduce his score of the final test, 1 day for 1 point. And as you know, doing homework always takes a long time. So Ignatius wants you to help him to arrange the order of doing homework to minimize the reduced score.
 

Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case start with a positive integer N(1<=N<=15) which indicate the number of homework. Then N lines follow. Each line contains a string S(the subject's name, each string will at most has 100 characters) and two integers D(the deadline of the subject), C(how many days will it take Ignatius to finish this subject's homework). 

Note: All the subject names are given in the alphabet increasing order. So you may process the problem much easier.
 

Output
For each test case, you should output the smallest total reduced score, then give out the order of the subjects, one subject in a line. If there are more than one orders, you should output the alphabet smallest one.
 

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

题意:有n门课,每门课有截止时间和完成所需的时间,如果超过规定时间完成,每超过一天就会扣1分,问怎样安排做作业的顺序才能使得所扣的分最小

思路:一开始我是想通过遍历所有的可能,也就是 !15 即 1e13的复杂度,太大了,所以我想用记忆化搜索的方式做,但是看到的所有的题解都是用循环做的,所以我比较了一下循环与记忆化搜索的区别,发现其实这种循环就是一种记忆化搜索,不过记忆化搜索和循环搜索的路径不同,比如记忆化搜索搜索状态111时,他需要搜索状态011、101、110,在搜索101时需要搜索100和001,向下dfs,而用循环的话,则是从1开始循环递增,也就是说当他计算状态111时,比111小的所有状态已经计算完毕。也就是说循环使搜索的方向确定了,但是循环的本质和记忆化搜索是一样的。(小白个人理解,如果大神们认为错误还请不吝赐教~)使用循环的状态dp就不再写了,可以参见这位大神的博客http://blog.csdn.net/xingyeyongheng/article/details/21742341  其中需要注意的就是状态111搜索101时,意思是将状态010加到状态101的最后,所以为了满足字典序,需要从后向前遍历。

下面贴上循环的解法:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define MAXX (1 << 17)
#define INF 0xffff
using namespace std;

char s[17][110];
int line[17];
int fee[17];

struct{
    int day;
    int score;
    int pre;
}dp[MAXX];

void output(int i){
    if(!i)return;
    output(i^ (1 << (dp[i].pre-1)) );
    printf("%s\n",s[ dp[i].pre ]);
}
int main(){

      int t,n;
      scanf("%d",&t);
      while(t--){

        scanf("%d",&n);
        int bit = 1 << n;
        for(int i = 1; i <= n; i++)
            scanf("%s%d%d",s[i],&line[i],&fee[i]);

        for(int i = 1; i < bit; i++){ //!!遍历状态
            dp[i].score = INF;
            for(int j = n; j >= 1; j--){
                int thej = 1 << (j-1);
                if(!(i&thej))continue;

                int temp = i^thej;
                int score = dp[temp].day+fee[j]-line[j];
                if(score < 0)score = 0;

                if(dp[i].score > dp[temp].score+score){
                    dp[i].day = dp[temp].day+fee[j];
                    dp[i].score = dp[temp].score+score;
                    dp[i].pre = j;
                }
            }
        }
        printf("%d\n",dp[bit-1].score);
        output(bit-1);
      }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值