D:课程大作业(dp)

D:课程大作业

描述

小明是北京大学信息科学技术学院三年级本科生。他喜欢参加各式各样的校园社团。这个学期就要结束了,每个课程大作业的截止时间也快到了,可是小明还没有开始做。每一门课程都有一个课程大作业,每个课程大作业都有截止时间。如果提交时间超过截止时间X天,那么他将会被扣掉X分。对于每个大作业,小明要花费一天或者若干天来完成。他不能同时做多个大作业,只有他完成了当前的项目,才可以开始一个新的项目。小明希望你可以帮助他规划出一个最好的办法(完成大作业的顺序)来减少扣分。

输入
输入包含若干测试样例。
输入的第一行是一个正整数T,代表测试样例数目。
对于每组测试样例,第一行为正整数N(1 <= N <= 15)代表课程数目。
接下来N行,每行包含一个字符串S(不多于50个字符)代表课程名称和两个整数D(代表大作业截止时间)和C(完成该大作业需要的时间)。
注意所有的课程在输入中出现的顺序按照字典序排列。

输出
对于每组测试样例,请输出最小的扣分以及相应的课程完成的顺序。
如果最优方案有多个,请输出字典序靠前的方案。

样例输入
2
3
Computer 3 3
English 20 1
Math 3 2
3
Computer 3 3
English 6 3
Math 6 3

样例输出
2
Computer
Math
English
3
Computer
English
Math

提示
第二个测试样例, 课程完成顺序Computer->English->Math 和 Computer->Math->English 都会造成3分罚分, 但是我们选择前者,因为在字典序中靠前.

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int MAXN = 1<<16;
int d[16] = {};//截止时间
int c[16] = {};//花费时间
string name[16] = {};
int timeC[MAXN] = {};
int penaC[MAXN] = {};
string ans[MAXN] = {};
int f(int a, int b){
    return max(0, a - b);
}
int main(){
    int t = 0;
    cin >> t;
    while(t--){
        int n = 0;
        memset(d, 0, sizeof(d));
        memset(c, 0, sizeof(c));
        memset(timeC, 0, sizeof(timeC));
        memset(penaC, 0, sizeof(penaC));
        cin >> n;
        for(int i = 0; i < n; ++i){
            cin >> name[i];
            cin >> d[i];
            cin >> c[i];
            timeC[1 << i] = c[i];
        }
        //计算花费时间
        for(int i = 1; i < (1<<n); ++i){
            for(int j = 0; j < n; ++j){
                if(i & (1 << j)){
                    timeC[i] = timeC[i ^ (1 << j)] + c[j];
                }
            }
        }
        //迭代用时
        penaC[0] = 0;
        for(int i = 0; i < (1 << n); ++i)
            ans[i] = "";
        for(int i = 1; i < (1 << n); ++i){
            for(int j = 0; j < n; ++j){
                if( i & (1 << j) && (penaC[i ^ (1 << j)] + f(timeC[i], d[j]) <= penaC[i] || ans[i] == "")){//如果(第j个被写了)且(罚时不超过原罚时或者这种做法的结果没有被迭代出来)
                    if(penaC[i ^ (1 << j)] + f(timeC[i], d[j]) < penaC[i] || ans[i ^ (1 << j)] + name[j] + "\n" < ans[i] || ans[i] == ""){
                        //如果(罚时比之前的罚时少)或者(字母序靠前)或者(没有做法结果)
                           ans[i] = ans[i ^ (1 << j)] + name[j] + "\n";
                       }
                    //更新罚时,其实是在<的时候才有意义
                     penaC[i] = penaC[i ^ (1 << j)] + f(timeC[i], d[j]);
                }
            }
        }
        cout << penaC[(1 << n) - 1] << endl << ans[(1 << n) - 1];
    }
    return 0;
}

你可能感兴趣的:(算法,算法)