D - Doing Homework HDU - 1074 (状态压缩DP)

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门课程作业的截止时间和完成所需时间,超出截止时间的天数就是要扣的分数,让你计算最少要见的分数和完成作业的先后顺序

思路:所有的这些课程只有完成和没完成两种状态,所以考虑用二进制来表示完成功课的状态,也就是状态压缩dp。其实说白了也就是枚举,只不过用动态规划的思路来解决时间复杂度会更低。我也是刚学状压dp,这也是我的个人理解~~~~

 

#include 
#include 
#define INF 0x3f3f3f3f
using namespace std;

struct node
{
   string name;
   int demand;
   int day;
}course[20];

struct DP{
    int now;           ///存放当前的时间
    int score;         ///存放当前减少的分数
    int pre;           ///存放前一个状态到达当前状态所完成的课程
}dp[1 << 16];

void output(int x)
{
    int ans[30];
    int l = 0;
    while(x)
    {
        ans[l++] = dp[x].pre;         
        x = x - (1 << dp[x].pre);             
    }
    for(int i = l-1; i >= 0; i--)
    {
        cout << course[ans[i]].name << endl;
    }

}

int main()
{
    //freopen("in.txt", "r", stdin);
    int t, n;
    cin >> t;
    while(t--)
    {
        cin >> n;
        for(int i = 0; i < n; i++)
        {
            cin >> course[i].name >> course[i].demand >> course[i].day;
        }
        dp[0].now = 0;
        dp[0].pre = -1;
        dp[0].score = 0;
        for(int i = 1; i < 1 << n; i++)
        {
            dp[i].score = INF;
        }
        for(int i = 0; i < 1 << n; i++)      ///枚举所有状态
        {
            for(int j = n -1; j >= 0; j--)      
            {
                int tmp = 1 << j;
                if(i & tmp)               ///如果第j门课程已经做了
                    continue;
                int tot = i | tmp;        ///加入第j门课程,到达当前状态
                int time = dp[i].now + course[j].day;       ///计算当前时间
                int sc = 0;                    
                if(time > course[j].demand)            ///如果时间超了就计算要被减去的分数
                {
                    sc = time - course[j].demand;
                }
                sc += dp[i].score;                  ///跟上一个状态的分数相加
                if(dp[tot].score > sc)              ///看是否能更新
                {
                    dp[tot].score = sc;
                    dp[tot].now = time;
                    dp[tot].pre = j;
                }
            }
        }
        cout << dp[(1 << n) - 1].score << endl;   ///找到所有功课都完成的状态的结果
        output((1<

第一次接触状压dp,感觉好神奇,用二进制表示状态太强了!!!

你可能感兴趣的:(状态压缩dp)