其他分享
首页 > 其他分享> > Day9 - G - Doing Homework HDU - 1074

Day9 - G - Doing Homework HDU - 1074

作者:互联网

有n个任务,每个任务有一个截止时间,超过截止时间一天,要扣一个分。
求如何安排任务,使得扣的分数最少。Input有多组测试数据。第一行一个整数表示测试数据的组数
第一行一个整数n(1<=n<=15)
接下来n行,每行一个字符串(长度不超过100)表示任务的名称和两个整数,分别表示任务的截止时间和完成任务需要的天数。 这n个任务是按照字符串的字典序从小到大给出。Output每组测试数据,输出最少扣的分数的。 并输出一个完成任务的方案,如果有多个方案,输出字典序最小的一个。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[i]表示i状态下的最小扣分,状态转移为dp[i] = min(dp[pre]+dp[pre].time-limit[j]),dp[pre].time表示pre状态下花费的总时间,j表示状态pre转移到i时是经过哪一个中间态,即:pre = i^(1<<j)

const int maxm = (1<<15)+5;

int finish[20], limit[20], n;

struct Node {
    int fa, task, ans, time;
} dp[maxm];

map<int, string> Cache;

void run_case() {
    Cache.clear();
    string str;
    cin >> n;
    for(int i = 0; i < n; ++i) {
        cin >> str >> limit[i] >> finish[i];
        Cache[i] = str;
    }
    for(int i = 1; i < (1<<n); ++i) {
        dp[i].ans = 0x3f3f3f3f;
        for(int j = n-1; j >= 0; --j) {
            if(i&(1<<j)) {
                int pre = i^(1<<j);
                int now = dp[pre].time+finish[j]-limit[j];
                if(now < 0) now = 0;
                if(now+dp[pre].ans<dp[i].ans) {
                    dp[i].fa = pre;
                    dp[i].task = j;
                    dp[i].ans = now+dp[pre].ans;
                    dp[i].time = dp[pre].time + finish[j];
                }
            }
        }
    }
    int End = (1<<n)-1;
    cout << dp[End].ans << "\n";
    vector<int> ans;
    while(End) {
        ans.push_back(dp[End].task);
        End = dp[End].fa;
    }
    for(auto i = ans.rbegin(); i != ans.rend(); ++i) {
        cout << Cache[*i] << "\n";
    }
    return;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    int T;
    cin >> T;
    while(T--) {
        run_case();
    }
    return 0;
}
View Code

 

标签:pre,HDU,End,Doing,1074,Computer,Math,English,dp
来源: https://www.cnblogs.com/GRedComeT/p/12243314.html