贪心算法:265.排队打水--系列
(2018-10-17 10:02:27)| 分类: 贪心 |
一、基本概念
所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。
二、基本思路
1.建立数学模型来描述问题。
2.把求解的问题分成若干个子问题。
3.对每一子问题求解,得到子问题的局部最优解。
4.把子问题的解局部最优解合成原来解问题的一个解。
三、适用问题
贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
四、实现框架
从问题的某一初始解出发;
while (能朝给定总目标前进一步)
{
利用可行的决策,求出可行解的一个解元素;
}
由所有解元素组合成问题的一个可行解;
五、贪心策略的选择
因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。
1)【例1】排队打水问题
有N个人排队到R个水龙头去打水,他们装满水桶的时间为T1,T2,…,Tn为整数且各不相等,应如何安排他们的打水顺序才能使他们花费的时间最少?
【算法分析】
由于排队时,越靠前面的计算的次数越多,显然越小的排在越前面得出的结果越小(可以用数学方法简单证明,这里就不再赘述),所以这道题可以用贪心法解答,基本步骤:
(1)将输入的时间按从小到大排序;
(2)将排序后的时间按顺序依次放入每个水龙头的队列中;
(3)统计,输出答案。
【样例输入】
4
2
//4人打水,2个水龙头
2 6 4
5
//每个打水时间
问题分析:
这题说“显然越小的排在越前面,得出的结果越小”,是草率的;
可以对比另一道题目,最佳调度问题 //blog.sina.com.cn/s/blog_13bd4d96a0102yo86.html
可以发现,其他条件和求解,都几乎一样,只有一个地方不同:本题要算上等待时间,那一题不用。
所以,“显然”只是对“只有一个水龙头”的情况下,是显然的;这样两题就可以得到统一;
在超出两个以上水龙头时,要证明它并不容易,(否则那一题也“很容易”证明了,实际上那样解就是错的),在接水问题上,是因为等待时间有累积性,这样随着ti而增加的离散化会非常大,从而令“不正确的可能性”得以忽略。
这只是说明一个问题:贪心不是一种完整的算法,只是一种“妥协”算法。
以下是本题的题解:
#include "bits/stdc++.h"
using namespace std;
int s[1000],a[1000];
int main(){
int
n,r;
cin>>n>>r;
for(int
i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int
j=0,minx=0;
for (int
i=1;i<=n;++i)
//用贪心法求解
{
j++; if (j==r+1)
j=1;
二、基本思路
三、适用问题
四、实现框架
五、贪心策略的选择
1)【例1】排队打水问题
【算法分析】
【样例输入】
问题分析:
这题说“显然越小的排在越前面,得出的结果越小”,是草率的;
可以对比另一道题目,最佳调度问题 //blog.sina.com.cn/s/blog_13bd4d96a0102yo86.html
可以发现,其他条件和求解,都几乎一样,只有一个地方不同:本题要算上等待时间,那一题不用。
所以,“显然”只是对“只有一个水龙头”的情况下,是显然的;这样两题就可以得到统一;
在超出两个以上水龙头时,要证明它并不容易,(否则那一题也“很容易”证明了,实际上那样解就是错的),在接水问题上,是因为等待时间有累积性,这样随着ti而增加的离散化会非常大,从而令“不正确的可能性”得以忽略。
这只是说明一个问题:贪心不是一种完整的算法,只是一种“妥协”算法。
以下是本题的题解:
#include "bits/stdc++.h"
using namespace std;
int s[1000],a[1000];
int main(){

加载中…