目标
1.学习如何处理不可能完成的任务:没有快速算法的问题(NP完全问题)。
2.学习识别NP完全问题,以免浪费时间寻找解决它们的快速算法。
3.学习近似算法,使用他们可快速找到NP完全问题的近似解。
4.学习贪婪策略——一种非常简单的问题解决策略。
教室调度问题
假设有如下课程表,你希望将尽可能多的课程安排在某间教室上。你设法让这些可都在这间教室上,但是有些课有冲突。你希望在这间教室尽可能多的上课。
贪婪算法可以让你简单的达到这个结果。
1)选出结束最早的课,它就是在这间教室上的第一节课。
2)选出第一节课结束后才开始的课。同样,你选择结束最早的课,这将是第二节课。
3)重复以上步骤。
贪婪算法的优点就是简单易行,每步都选择局部最优解,最终得到的就是全局最优解。并非在任何情况下都行之有效,但是它易于实现。
NP完全问题
旅行商问题:
有一位旅行商,他需要前往5个城市。
这位旅行商要前往这五个城市,同时需要保证旅程最短。为此,可考虑前往这五个城市的各种可能顺序。
对于每种顺序,都需要计算总旅程,在挑选出旅程最短的路线。5个城市有120种可能,6个则有720种,7个有5040种,这个问题的大O表达式是O(n!) 。
阶乘:
每当多增加一个城市时,需要计算的可能就更多。因此,如果涉及的城市很多的多,根本无法找到正确的解。
NP完全问题定义:没有全局最优解的问题。
最少硬币找零问题
最少硬币找零是给出要找零的钱数,以及可以用硬币的额度数量,找出有多少种找零方法。
如:美国面额硬币有:1,5,10,25
我们给36美分的零钱,看能得怎样的结果?
function MinCoinChange(coins){
let coins = coins;
let cache = {};
this.makeChange = function(amount){
let change = [], total = 0;
//从最大面额开始
for(let i = coins.length; i >= 0; i--){
let coin = coins[i];
//当前面额小于剩余需要零钱
while(total + coin <= amount){
change.push(coin);
total += coin;
}
}
return change;
}
}
//确定面额
var minCoinChange = new MinCoinChange([1, 5, 10, 25]);
minCoinChange.makeChange(36);
//一个25, 一个10, 一个1
近似算法
解决旅行商问题
1.选定出发城市
2.每次选择最近的要去的城市
3.重复以上步骤
近似不是最优解,怎么判断近似算法优劣:
1.速度有多快,贪婪算法大O表达式O(n)
2.得到的近似解于最优解的接近程度。
如何识别NP完全问题
没有办法判断问题是不是NP完全问题,但还是有一些规律的
元素较少时算法的运行速度非常快,但随着元素数量增加,速度会变慢。
涉及“所有组合”的问题通常是NP完全问题
不能将问题分成小问题,必须考虑所有可能的情况,可能是NP完全问题。
涉及序列且难以解决,可能是NP完全问题。
涉及集合且难以解决,可能是NP完全问题。
问题可以转换成集合问题和旅行商问题,肯定是NP完全问题。
小结
贪婪算法寻找局部最优解,企图以这种方式获得全局最优解。
对于NP完全问题,还么有找到快速解决方案。
面对NOP完全问题是,最佳的做法是使用近似算法。
贪婪算法易于实现、运行速度快,是不错的近似算法。