课程调度问题

题目来源:

网易云课堂  算法设计与分析之入门篇 贪心算法 作业3

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

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

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

输入样例: 

2 2 2 

4 1 2 

1 3 2 1 
输出样例: 


7

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

题目分析:

 理解一下题意,说的是把两个{ai}1<=i<=n中的元素分别排好,并且不能重叠。

 这个问题难在如何找到一个好的策略来调度,只要找到这样一个调度策略,证明它是总时间最少的策略就可以了,代码部分并不难。

为讨论方便,我们假设a1<=...<=ai<=...<=an

 显然,我们最希望看到的解是所有ai的和。在这种情况下,所有的课程都没有重叠。我们可以看看重叠的情况,亦即样例2:

4444221_

221_4444

由于重叠,第二行的课程4必须往后挪一位,导致总时间增加。为减少重叠,我采用了以下的策略:

an       a(n-1) a(n-2) ... a2 a1

a(n-1) a(n-2)            ... a1 an

假设从0开始计数,所以上面一行ai(i<n) 的开始时间为an+...+a(i+1) ,下面一行ai  的结束时间为

a(n-1)+...+ai ,由于ai<=a(i+1)  (i<n) ,所以上面一行ai开始时间总大于下面一行ai。

通过循环移动一位,我发现整个策略里唯一可能重叠的课程就是最大的an了。当 2 * an <= an +...+a1 时,an不重叠,所有的课程都不重叠,最小的总时间为所有课程时间之和;否则,an重叠,最小的总时间为2 * an 。


回到实现部分,我们只需要遍历一下数组,找到最大的元素,同时求出最大值,比较最大值的两倍和所有元素之和就可以了。同时注意一下给的数有可能会溢出,选大一点的long long就行了。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef unsigned int uint_32;
typedef unsigned long long uint_64;
uint_64 GetMinCourseTime(vector<uint_32>& courses) {
	if ( courses.size() == 0 ) return 0;
	uint_64 sum = 0;
	uint_64 maxnum = courses[0];
	for (uint_32 i = 0; i < courses.size(); i++) {
		if (maxnum < courses[i])maxnum = courses[i];
		sum += courses[i];
	}
	return 2*maxnum>sum?2*maxnum:sum;
}

int main() {
	uint_32 n = 0;
	cin >> n;
	vector<uint_32> scores;
	for (uint_32 i = 0; i < n; i++) {
		uint_32 ele = 0;
		cin >> ele;
		scores.push_back(ele);
	}
	cout << GetMinCourseTime(scores) << "\r\n";
	system("pause");
	return 0;
}








评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值