11089 多机最佳调度(优先做)
时间限制:20000MS 代码长度限制:10KB
提交次数:0 通过次数:0
题型: 编程题 语言: G++;GCC;VC;JAVA
Description
假设有n个任务(n<=100),m台机器(m<=50),任务可以由任何一个机器完成,但不可以拆分任务或执行过程中中途停下, 第i个任务完成需要的时间为ti, 请设计两种算法(一种采用贪心算法,另一种采用回溯算法),找出完成这n个任务的最佳调度,使得最早时间完成全部任务。 这里采用两种算法来求解: 1)贪心算法可以得到近似的最早完成时间,算法思想在书上4.7节。 2)回溯算法搜索m叉树(除叶节点外每个节点m个儿子),寻找最早的完成时间。
输入格式
输入两行,第一行为n和m,中间空格相连(其中n表示任务的数量,m表示机器的数量),(n<=100, m<=50)。 第二行的n个数是任务i的处理时间ti。
输出格式
输出两行,第一行为采用贪心算法算出的最早完成时间,第二行为采用回溯算法搜索出的最早完成时间。
输入样例
7 3 2 14 4 16 6 5 3 另一个输入示例: 14 3 10 10 10 10 10 7 7 7 7 7 5 5 5 5
输出样例
17 17 另一个输出示例: 37 35
提示
第(1)个贪心算法按书上思想去实现:总将更长的作业分给最早空闲的机器。 第(2)个就是在m叉树上深度优先搜寻最优解的过程。 //t数组为初始的任务处理时间; //len2是个数组:m个元素对应m台机的空闲时间,即第二种回溯算法在搜索过程中已探察过任务且针对某台机的完成时间和; //x数组用来保存探察过的任务编号。 void backtrack (int dep) { if (dep == n) //叶子,或者if (dep>n),看首次调用backtrack参数是0还是1 { …… //这个省略号,要你自己来扩展了,要找到最好的叶子(即最早完成时间的一组最优调度) return; } for(int i = 0; i < m; i++) { len2[i] += t[dep]; //len2数组和t数组如上说明 x[dep] = i+1; if(len2[i] < best) backtrack(dep+1); len2[i] -= t[dep]; } }
作者
zhengchan
解题思路
一、贪心算法
总将更长的作业分给最早空闲的机器。
图解的方式直观的感受贪心算法的过程:
先将作业降序排序:{16,14,6,5,4,3,2}
M1:16
M2:14+3=17
M3:6+5+4+2=17
最早全部完成时间为17
二、回溯算法
在m叉树上深度优先搜寻最优解。
三、代码实现
#include<iostream>
#include<algorithm>
using namespace std;
int n, m;
int len2[51] = {0};
int t[101] = {0};
int x[101] = {0};
int best = 0;
// 降序排序
bool cmp(int a, int b){
return a > b;
}
// 贪心算法
void greedy(){
sort(t, t+n, cmp);
for(int i = 0; i < m; i++)
len2[i] = 0;
for(int i = 0; i < n; i++){
int maxLen = len2[0];
int index = 0;
for(int j = 0; j < m; j++){
// 将更长的作业分给最早空闲的机器
if(len2[j] < maxLen){
maxLen = len2[j]; // 更新最长作业长度
index = j;
}
}
len2[index] += t[i];
}
for(int i = 0; i < m; i++)
best = max(best, len2[i]);
}
// 回溯算法
void backtrack(int dep){
if(dep == n){
int maxLen = 0;
for(int i = 0; i < m; i++)
maxLen = max(maxLen, len2[i]);
best = min(best, maxLen);
return;
}
for(int i = 0; i < m; i++){
len2[i] += t[dep];
x[dep] = i+1;
if(len2[i] < best)
backtrack(dep+1);
len2[i] -= t[dep];
}
}
int main()
{
cin >> n >> m;
for(int i = 0; i < n; i++)
cin >> t[i];
greedy();
cout << best << endl;
best = INT16_MAX; // 重置最佳值
for(int i = 0; i < m; i++)
len2[i] = 0; // 重置长度数组
backtrack(0);
cout << best << endl;
return 0;
}