正在网易云课堂学习王宏志老师的算法设计与分析入门篇课程视频,将学习中的作业问题发上来与大家一同讨论。这篇是对第五周的作业第三题个人的一些思路,希望与大家一同学习。
课程调度
题目内容:
有 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。