贪心算法作业调度
① java代码,多机调度问题,怎么解释
多机调度问题的Java实现(贪心算法)
具体问题描述以及C/C++实现参见网址
[java]viewplainprint?
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.LinkedList;
importjava.util.List;
/**
*多机调度问题--贪心算法
*@authorLican
*
*/
publicclassJobMachine{
{
intid;//作业的标号
inttime;//作业时间
publicJobNode(intid,inttime){
this.id=id;
this.time=time;
}
@Override
publicintcompareTo(Objectx){//按时间从大到小排列
inttimes=((JobNode)x).time;
if(time>times)return-1;
if(time==times)return0;
return1;
}
}
{
intid;//机器的标号
intavail;//机器空闲的时间(即机器做完某一项工作的时间)
publicMachineNode(intid,intavail){
this.id=id;
this.avail=avail;
}
@Override
publicintcompareTo(Objecto){//升序排序,LinkedList的first为最小的
intxs=((MachineNode)o).avail;
if(avail<xs)return-1;
if(avail==xs)return0;
return1;
}
}
publicstaticintgreedy(int[]a,intm){
intn=a.length-1;//a的下标从1开始,所以n(作业的数目)=a.length-1
intsum=0;
if(n<=m){
for(inti=0;i<n;i++)
sum+=a[i+1];
System.out.println("为每个作业分别分配一台机器");
returnsum;
}
List<JobNode>d=newArrayList<JobNode>();//d保存所有的作业
for(inti=0;i<n;i++){//将所有的作业存入List中,每一项包含标号和时间
JobNodejb=newJobNode(i+1,a[i+1]);
d.add(jb);
}
Collections.sort(d);//对作业的List进行排序
LinkedList<MachineNode>h=newLinkedList<MachineNode>();//h保存所有的机器
for(inti=1;i<=m;i++){//将所有的机器存入LinkedList中
MachineNodex=newMachineNode(i,0);//初始时,每台机器的空闲时间(完成上一个作业的时间)都为0
h.add(x);
}
inttest=h.size();
for(inti=0;i<n;i++){
Collections.sort(h);
MachineNodex=h.peek();
System.out.println("将机器"+x.id+"从"+x.avail+"到"+(x.avail+d.get(i).time)+"的时间段分配给作业"+d.get(i).id);
x.avail+=d.get(i).time;
sum=x.avail;
}
returnsum;
}
publicstaticvoidmain(String[]args){
int[]a={0,2,14,4,16,6,5,3};
intm=3;
intsum=greedy(a,m);
System.out.println("总时间为:"+sum);
}
}
/**
运行结果:
将机器1从0到16的时间段分配给作业4
将机器2从0到14的时间段分配给作业2
将机器3从0到6的时间段分配给作业5
将机器3从6到11的时间段分配给作业6
将机器3从11到15的时间段分配给作业3
将机器2从14到17的时间段分配给作业7
将机器3从15到17的时间段分配给作业1
总时间为:17
*/
② 分治、贪心五大算法
1、分治
分治(即分而治喊孙之),把一个复杂的问题分成多郑激链个相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
适用场景:二分搜索、归并排序、快速排序、大整数乘法、第K小元素、最近点对、快速傅里叶变换等。
2、动态规划
动态规划法也是把问题一层一层地分解为规模逐渐减小的同类型的子问题。动态规划通常用来求最优化问题。此类问题可以有很多可行解,我们求出的是一个最优解,可能存在多个最优解。(最优子结构、公共子问题)
与分治法的区别是:分治的子问题是相互独立的,动态规划最好解决有公共子问题的,子问题相关性很大。
使用场景:矩阵连乘、钢条切割、最长公共子序列、最优二叉搜索树、流水作业调度、0/1背包问题等。
维特比算法是动态规划在HMM中的应用,维特比算法用于解决HMM的预测或者叫解码问题。
viterbi有最优解是因为HMM每一步是条件独立的!既然后面的概率和前面的没关系,那前面选最大的概率就行了。
而beam search时后面的概率依赖于前面所有的词,相当于n-gram是满的,viterbi的n-gram是2
背包问题:
https://blog.csdn.net/wind__chaser/article/details/89457771
https://blog.csdn.net/qq_38410730/article/details/81667885
3、贪心
通过局部最优选择达铅吵到全局最优选择。贪心算法不一定总产生最优解,贪心算法是否产生优化解,需严格证明贪心算法产生最优解的条件:(最优子结构、贪心选择性)
贪心选择性:当一个问题的全局最优解可以通过局部最优解得到,称这个问题具有贪心选择性。
适用场景:活动选择问题、哈夫曼编码问题、最小生成树问题、单源最短路径问题等。
贪心算法:softmax之后取最大概率。与之对应的是,Beam Search算法
http://www.360doc.com/content/18/0618/09/17563728_763230413.shtml
https://blog.csdn.net/qq_16234613/article/details/83012046
https://www.hu.com/question/54356960
分治和动态规划的区别:
动态规划也是一种分治思想(比如其状态转移方程就是一种分治),但与分治算法不同的是,分治算法是把原问题分解为若干个子问题,
自顶向下求解子问题,合并子问题的解,从而得到原问题的解。动态规划也是把原始问题分解为若干个子问题,然后自底向上,
先求解最小的子问题,把结果存在表格中,在求解大的子问题时,直接从表格中查询小的子问题的解,避免重复计算,从而提高算法效率。
动态规划和分治法有些相像,都是把一个问题分成了很多子问题来求解,但是不同的是动态规划会记忆之前解决的子问题的结果,
避免了重复计算。判断一个问题是否能用动态规划求解,要看它是否能划分成合适的子问题,然后写出递推关系式。
动态规划得到的解一定是最优解。
③ 最佳调度问题(c/c++)
如果各机器运行速度相等,换句话就是任务无论在哪台机器上运行完成时间都相等,则问题较简单
1 . 先将任务由大到小排序
2 . 计算n个任务需要的总时间和平均到k个机器上的时间
3 . 将大于平均时间的任务各分配一个机器,找到最大完成时间
4 . 将其他任务顺序安排在一台机器上,如果时间超出最大时间,则把该任务交给下一个机器,下一个任务继续在这台机器上试安排,直到所有任务都不能在小于最大完成时间的情况下安排
5 . 安排下一台机器直道所有任务安排完,
6 . 或有可能安排某(些)任务找不到小于最大完成时间 那么重新扫描各台机器使再加上该任务后时间最小,按此方法安排万所有任物
数据结构采用链表比较合适,
K个机器k个链,n个任务按大小顺序插入一个链表,安排后从任务链表中移动到机器链表中。知道链表为空
④ 贪心算法
#include <stdio.h>
#define M 100
void main()
{
int i,j,k,temp,m,n;
int t[M]={2,14,4,16,6,5,3},p[M]={1,2,3,4,5,6,7},s[M],d[M]={0};
m=3;n=7;
for(i=0;i<7;i++)
for(j=0;j<7-i;j++)
if(t[j]<t[j+1])
{
temp=t[j];
t[j]=t[j+1];
t[j+1]=temp;
temp=p[j];
p[j]=p[j+1];
p[j+1]=temp;
}
for(i=0;i<m;i++) //求时间。
{
s[i]=p[i];
d[i]=t[i];
}
for(k=0;k<m;k++)
printf(" %d",d[k]);
printf("\n");
for(i=m;i<n;i++)
{
for(k=0;k<m-1;k++) //求最小。
{
temp=d[k];
if(temp>d[k+1])
{temp=d[k+1];j=k+1;}
}
printf("这是最小下标的: %d\n",j);
printf("最小的值: %d\n",temp);
for(k=0;k<m;k++)
printf(" %d",d[k]);
printf("\n");
//j=temp;
s[j]=s[j]+p[i];
d[j]=d[j]+t[i];
}
printf("\n");
for(k=0;k<7;k++)
printf(" %d",t[k]);
printf("\n");
for(k=0;k<7;k++)
printf(" %d",p[k]);
printf("\n");
for(k=0;k<m;k++)
printf(" %d",s[k]);
printf("\n");
for(k=0;k<m;k++)
printf(" %d",d[k]);
printf("\n");
}
⑤ 算法怎么学
贪心算法的定义:
贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的一般步骤是:
1.建立数学模型来描述问题;
2.把求解的问题分成若干个子问题;
3.对每一子问题求解,得到子问题的局部最优解;
4.把子问题的局部最优解合成原来问题的一个解。
如果大家比较了解动态规划,就会发现它们之间的相似之处。最优解问题大部分都可以拆分成一个个的子问题,把解空间的遍历视作对子问题树的遍历,则以某种形式对树整个的遍历一遍就可以求出最优解,大部分情况下这是不可行的。贪心算法和动态规划本质上是对子问题树的一种修剪,两种算法要求问题都具有的一个性质就是子问题最优性(组成最优解的每一个子问题的解,对于这个子问题本身肯定也是最优的)。动态规划方法代表了这一类问题的一般解法,我们自底向上构造子问题的解,对每一个子树的根,求出下面每一个叶子的值,并且以其中的最优值作为自身的值,其它的值舍弃。而贪心算法是动态规划方法的一个特例,可以证明每一个子树的根的值不取决于下面叶子的值,而只取决于当前问题的状况。换句话说,不需要知道一个节点所有子树的情况,就可以求出这个节点的值。由于贪心算法的这个特性,它对解空间树的遍历不需要自底向上,而只需要自根开始,选择最优的路,一直走到底就可以了。
话不多说,我们来看几个具体的例子慢慢理解它:
1.活动选择问题
这是《算法导论》上的例子,也是一个非常经典的问题。有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。
关于贪心算法的基础知识就简要介绍到这里,希望能作为大家继续深入学习的基础。
⑥ 姣忓ぉ涓涓鐭ヨ瘑镣癸细璐濠绠楁硶钬斺斾竴涓绠鍗旷殑璋冨害闂棰
鍓嶆彁鏄浣跨敤闱为勫崰璋冨害(nonpreemptive scheling)锛氩嵆涓镞﹀紑濮嬩竴涓浣滀笟锛屽氨蹇呴’鎶婅ヤ綔涓氲繍琛屽畬銆
锅囱剧幇鍦ㄦ湁锲涗釜浣滀笟锛
璇ヨ皟搴︽荤殑浠d环 C 涓
鍗筹细
鍙浠ョ湅鍒帮纴绗涓涓姹傚拰涓庝綔涓氱殑鎺掑簭镞犲叧锛屽洜姝ゅ彧链夌浜屼釜姹傚拰褰卞搷鍒版诲紑阌銆傝惧湪涓涓鎺掑簭涓瀛桦湪 x > y 浣垮缑 < 銆傛ゆ椂锛岃$畻琛ㄦ槑锛屼氦鎹 鍜 锛岀浜屼釜鍜屽炲姞锛屼粠钥岄檷浣庝简镐荤殑寮阌銆傚洜姝わ纴镓鐢ㄦ椂闂翠笉鏄鍗曡皟闱炲噺镄勪换浣旷殑浣滀笟璋冨害蹇呯劧鏄娆′紭镄勚傚墿涓嬬殑鍙链夐偅浜涘叾浣滀笟鎸夌収链灏忚繍琛屾椂闂存渶鍏埚畨鎺掔殑璋冨害鏄镓链夎皟搴︽柟妗堜腑链浼樼殑銆
杩欎釜缁撴灉鎸囧嚭涓轰粈涔堟搷浣灭郴缁熻皟搴︾▼搴忎竴鑸鎶娄紭鍏堟潈璧嬩篑闾d簺镟寸煭镄勪綔涓氥
闱为勫崰璋冨害镄勫墠鎻愪笉鍙桡纴锅囱剧幇鍦ㄦ湁涔濅釜浣滀笟锛
瑙e喅澶氩勭悊鍣ㄦ儏褰㈢殑绠楁硶鏄鎸夌収椤哄簭寮濮嬩綔涓氾纴澶勭悊鍣ㄤ箣闂磋疆鎹㈠垎閰崭綔涓氥备笉闅捐瘉鏄庢病链夊摢涓鍏朵粬镄勯‘搴忚兘澶熷仛寰楁洿濂斤纴铏界劧澶勭悊鍣ㄤ釜鏁 P 鑳藉熸暣闄や綔涓氭暟 N 镞跺瓨鍦ㄨ稿氭渶浼樼殑椤哄簭銆
鍗充娇 P 涓嶆伆濂芥暣闄 N锛屽摢镐曟墍链夌殑浣滀笟镞堕棿鏄浜掑纾镄勶纴涔熻缮鏄链夎稿氭渶浼樿В銆
灏嗗畬鎴愭椂闂存渶灏忓寲锛屽嵆鏁翠釜搴忓垪镄勫畬鎴愭椂闂存洿镞┿