算法设计与分析入门篇----贪心法3

本文探讨了在给定时间需求的情况下,如何最高效地安排个人完成两门课程的学习,涉及课程调度算法的设计与实现。通过模拟选择最合适的人选进行课程学习,以确保所有人都能在最短时间内完成所有课程。

正在网易云课堂学习王宏志老师的算法设计与分析入门篇课程视频,将学习中的作业问题发上来与大家一同讨论。这篇是对第五周的作业第三题个人的一些思路,希望与大家一同学习。

课程调度

题目内容:
有 n 个人,要完成 2 门课程。其中第 i 个人学习一门课程所需要的时间是 ti。
每个人同一时刻只能修一门课程,每门课程同一时刻只能被一个人修,中间不能中断。
问所有人都修完 2 门课程,至少需要多少时间。

输入格式:
输入的第一行包含一个整数 n(1 <= n <= 1000000)。
接下来的一行包含 n 个整数 (1 <= ai <= 1000000000),表示每门课程的时间。

输出格式:
输出一行表示对应的答案。

输入样例:
3
2 2 2
3
4 1 2
4
1 3 2 1
输出样例:
6
8
7

时间限制:2000ms内存限制:128000kb

思路是模拟两个课程不断挑选最合适的人来学,最合适的人 两门课都没学,并且学的时间是剩余最长的。其次学完一门,学的时间是剩余最长的。

#include <iostream>
#include <vector>
using namespace std;
void max(int& class1, int class2, int &sum, int k, vector<vector<int>> &p) {
    int max = -1;
    class1 = -1;
    for (int i = 0; i < p.size(); i++){
        if (max < p[i][1 - k] && (p[i][k] != 0) && (i != class2 || p[class2][1 - k] == 0)){
            class1 = i;
            max = p[i][1 - k];
        }
    }
}
int main(){
    int n;
    while (cin >> n){
        int sum = 0, count = 0;
        int class1 = -1, class2 = -1;
        vector<vector <int>> p(n, vector<int>(2));
        for (int i = 0; i < n; i++){
            cin >> p[i][0];
            p[i][1] = p[i][0];
        }
        while (sum != 2 * n){
            if (class1 < 0 || p[class1][0] == 0){
                max(class1, class2, sum, 0, p);
            }
            if (class2 < 0 || p[class2][1] == 0){
                max(class2, class1, sum, 1, p);
            }
            if (class1 >= 0 && p[class1][0]>0)
                if (--p[class1][0] == 0)
                    sum++;
            if (class2 >= 0 && p[class2][1]>0)
                if (--p[class2][1] == 0)
                    sum++;
            count++;
        }
        cout << count << "\r\n";
    }
    system("pause");
}

用例1过了,2超时

#include <iostream>
#include <vector>
using namespace std;
void max(int& class1, int class2, int &sum, int k, vector<vector<int>> &p) {
    int max = -1;
    class1 = -1;
    for (int i = 0; i < p.size(); i++){
        if (max < p[i][1 - k] && (p[i][k] != 0) && (i != class2 || p[class2][1 - k] == 0)){
            class1 = i;
            max = p[i][1 - k];
        }
    }
}
int main(){
    int n;
    while (cin >> n){
        int sum = 0, count = 0;
        int class1 = -1, class2 = -1;
        vector<vector <int>> p(n, vector<int>(2));
        for (int i = 0; i < n; i++){
            cin >> p[i][0];
            p[i][1] = p[i][0];
        }
        while (sum != 2 * n){
            if (class1 < 0 || p[class1][0] == 0){
                max(class1, class2, sum, 0, p);
            }
            if (class2 < 0 || p[class2][1] == 0){
                max(class2, class1, sum, 1, p);
            }
            if (class1 >= 0 && p[class1][0]>0)
                if (--p[class1][0] == 0){
                    sum++;
                    if (p[class1][1] == 0){
                        p.erase(p.begin() + class1);
                        if (class2 > class1)
                            class2--;
                        class1 = -1;
                    }
                }
            if (class2 >= 0 && p[class2][1]>0)
                if (--p[class2][1] == 0){
                    sum++;
                    if (p[class2][0] == 0){
                        p.erase(p.begin() + class2);
                        if (class1 > class2)
                            class1--;
                        class2 = -1;
                    }
                }
            count++;
        }
        cout << count << "\r\n";
    }
    system("pause");
}

用例1过了,2超时
再改

#include <iostream>
#include <vector>
using namespace std;
void max(int& class1, int class2, int &sum, int k, vector<vector<int>> &p) {
    int max = -1;
    class1 = -1;
    for (int i = 0; i < p.size(); i++){
        if (max < p[i][1 - k] && (p[i][k] != 0) && (i != class2 || p[class2][1 - k] == 0)){
            class1 = i;
            max = p[i][1 - k];
        }
    }
}
int min(int a, int b){
    return a < b ? a : b;
}
int main(){
    int n;
    while (cin >> n){
        int sum = 0, count = 0;
        int class1 = -1, class2 = -1;
        vector<vector <int>> p(n, vector<int>(2));
        for (int i = 0; i < n; i++){
            cin >> p[i][0];
            p[i][1] = p[i][0];
        }
        while (sum != 2 * n){
            if (class1 < 0 || p[class1][0] == 0){
                max(class1, class2, sum, 0, p);
            }
            if (class2 < 0 || p[class2][1] == 0){
                max(class2, class1, sum, 1, p);
            }
            int classmin;
            if (class1 == -1){
                classmin = p[class2][1];
                p[class2][1] = 0;
            }
            else if (class2 == -1){
                classmin = p[class1][0];
                p[class1][0] = 0;
            }
            else{
                classmin = min(p[class1][0], p[class2][1]);
                p[class1][0] = p[class1][0] - classmin;
                p[class2][1] = p[class2][1] - classmin;
            }
            if (class1 >= 0)
                if (p[class1][0] == 0){
                    sum++;
                    if (p[class1][1] == 0){
                        p.erase(p.begin() + class1);
                        if (class2 > class1)
                            class2--;
                        class1 = -1;
                    }
                }
            if (class2 >= 0)
                if (p[class2][1] == 0){
                    sum++;
                    if (p[class2][0] == 0){
                        p.erase(p.begin() + class2);
                        if (class1 > class2)
                            class1--;
                        class2 = -1;
                    }
                }
            count += classmin;
        }
        cout << count << "\r\n";
    }
    system("pause");
}

还是超时,越改越慢。然后就发现这道题其实很简单,
思路,求出学一门课时间最长的人所需要的时间,即给的数组的最大值max。求出数组的和,结果就是2*max 与数组的和两个数中大的那个。
代码如下:

#include <iostream>
using namespace std;
int main(){
    int n;
    while (cin >> n){
        int sum = 0, max = 0, data;
        for (int i = 0; i < n; i++){
            cin >> data;
            if (data > max){
                sum += max;
                max = data;
            }
            else{
                sum += data;
            }
        }
        if (max > sum)
            cout << 2 * max << "\r\n";
        else
            cout << max + sum << "\r\n";
    }
    system("pause");
}

证明方法:
为了简单说明先排个序,实际上不用。
k1 k2 k3 …………kn 从大到小
先说一下,学完的最短时间就是数组的和,而时间会比它长是因为第一节课与第二节课产生了冲突,即一个人正在学第一节课,而第二节课没学的也只剩他一个了,所以要学完第二节课必须等他学完第一节课。
第一门课从k1开始学 k1 k2 k3….
第二门课从kn开始学 kn kn-1 kn-2 ……..
则两门课会相遇,设在第m个人处相遇即在km处
若m!=1,则第二门课从km+1跳到k1处,由于k1>=km,所以当第一个人的第二门课学完后第m个人的第一门课也一定学完。则第一门课与第二门课就不会有冲突了。(任意一个人至少学了一门课)所用时间为 k1 + k2 + k3………+kn
若m==1(k1>k2+k3+….+kn),则第二节课要等第一个人把第一节课学完才能让他学习第二节课,第一个人学完第一节课后再学第二节,因为(k1>k2+k3+….+kn),所以当他学完第二节课后,其他人也早将第一节课学完了,所用时间为 2*k1
上面程序中的 sum 是 k2+k3+….+kn,max 是 k1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值