简单理解算法篇--贪心算法
贪心算法是什么意思?举个例子就很清楚了:现在你有一个能装4斤苹果的袋子,苹果有两种,一种3斤一个,一种2斤一个,怎么装才能得到最多苹果?当然我们人考虑的话当然是拿两个2斤的苹果,就刚好装满了,但是如果按贪心算法拿的话,首先就要把最重的苹果拿下(是不是很符合贪心两个字?),但并没有得到最多苹果。
贪心算法保证了局部最优,但并不能保证得到最优解。
什么时候用贪心法?满足下面两个条件
1.
具有最优子结构
2.
贪心选择性
第1点跟动态规划的条件一样,其实贪心跟动态规划一样,都是解决最优化的问题,而求解最优化问题通常又通过一系列的求解子问题的步骤。
第2点看个例子在说
现在有个活动选择的问题如下:
学校只有一个教室,下面表格i代表活动的编号,s代表活动开始时间,f代表活动结束时间.
i
1
2
3
4
5
6
7
8
9
10
11
s
1
3
0
5
3
5
6
8
8
2
12
f
4
5
6
7
9
9
10
11
12
14
16
现在问题是怎么合理分配才能让教室利用最大化(求活动序列A)?
如果用动态规划做的话思想可能是这样的,假设我已经知道第k个活动是活动序列之一,
那么又把1到k和k到11看做两个子问题继续分下去……(是不是感觉很麻烦- -)
用贪心法的话思想很简单:活动越早结束,剩余的时间是不是越多?那我就早最早结束的那个活动,找到后在剩下的活动中再找最早结束的不就得了?
虽然贪心算法的思想简单,但是贪心法不保证能得到问题的最优解,如果得不到最优解,那就不是我们想要的东西了,所以我们现在要证明的是在这个问题中,用贪心法能得到最优解。
现在要证明的是:
S是所有活动的集合,令m为活动集中最早结束的活动,则m在A活动序列中(A就是我们要求出的那个活动序列)。
证明:设j为A中最早结束的活动,如果m=j,那么就证明了最早结束活动m在A中,如果m!=j,
那么我们把j从A中剔除掉,然后换上m,依然能得到一个最优活动序列(m是所有活动中最早结束的),所以贪心法在这个问题里能得到最优解。
现在回过来看什么是贪心选择性质?就是能用贪心法得到得到全局最优解的性质,至于什么时候能获得,那就得自己判断了。
下面是实现的代码
static void Main(string[] args)
{
int[] s = new int[]
{0,1,3,0,5,3,5,6,8,8,2,12}; //活动开始时间,为了方便计算加入第0个活动,不影响
int[] f = new int[]
{0,4,5,6,7,9,9,0,10,11,12,14,16}; //活动结束时间
Console.WriteLine(RAS(s,f,0,11));
}
public static string RAS(int[] s,int[] f,int k,int n)//k为从第k个活动到第n个活动选出最优活动
{
int m = k + 1;
while (m <= n
&& s[m] < f[k])
{
m = m + 1;
}
if (m <= n)
{
return m + "," + RAS(s, f, m, n);
}
else
{
return null;
}
}
To be continued。。。。。。
贪心算法是什么意思?举个例子就很清楚了:现在你有一个能装4斤苹果的袋子,苹果有两种,一种3斤一个,一种2斤一个,怎么装才能得到最多苹果?当然我们人考虑的话当然是拿两个2斤的苹果,就刚好装满了,但是如果按贪心算法拿的话,首先就要把最重的苹果拿下(是不是很符合贪心两个字?),但并没有得到最多苹果。
贪心算法保证了局部最优,但并不能保证得到最优解。
什么时候用贪心法?满足下面两个条件
1.
具有最优子结构
2.
贪心选择性
第1点跟动态规划的条件一样,其实贪心跟动态规划一样,都是解决最优化的问题,而求解最优化问题通常又通过一系列的求解子问题的步骤。
第2点看个例子在说
现在有个活动选择的问题如下:
学校只有一个教室,下面表格i代表活动的编号,s代表活动开始时间,f代表活动结束时间.
i |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
s |
1 |
3 |
0 |
5 |
3 |
5 |
6 |
8 |
8 |
2 |
12 |
f |
4 |
5 |
6 |
7 |
9 |
9 |
10 |
11 |
12 |
14 |
16 |
现在问题是怎么合理分配才能让教室利用最大化(求活动序列A)?
如果用动态规划做的话思想可能是这样的,假设我已经知道第k个活动是活动序列之一,
那么又把1到k和k到11看做两个子问题继续分下去……(是不是感觉很麻烦- -)
用贪心法的话思想很简单:活动越早结束,剩余的时间是不是越多?那我就早最早结束的那个活动,找到后在剩下的活动中再找最早结束的不就得了?
虽然贪心算法的思想简单,但是贪心法不保证能得到问题的最优解,如果得不到最优解,那就不是我们想要的东西了,所以我们现在要证明的是在这个问题中,用贪心法能得到最优解。
现在要证明的是:
S是所有活动的集合,令m为活动集中最早结束的活动,则m在A活动序列中(A就是我们要求出的那个活动序列)。
证明:设j为A中最早结束的活动,如果m=j,那么就证明了最早结束活动m在A中,如果m!=j,
那么我们把j从A中剔除掉,然后换上m,依然能得到一个最优活动序列(m是所有活动中最早结束的),所以贪心法在这个问题里能得到最优解。
现在回过来看什么是贪心选择性质?就是能用贪心法得到得到全局最优解的性质,至于什么时候能获得,那就得自己判断了。
下面是实现的代码
static void Main(string[] args)
{
int[] s = new int[]
{0,1,3,0,5,3,5,6,8,8,2,12}; //活动开始时间,为了方便计算加入第0个活动,不影响
int[] f = new int[]
{0,4,5,6,7,9,9,0,10,11,12,14,16}; //活动结束时间
Console.WriteLine(RAS(s,f,0,11));
}
public static string RAS(int[] s,int[] f,int k,int n)//k为从第k个活动到第n个活动选出最优活动
{
int m = k + 1;
while (m <= n
&& s[m] < f[k])
{
m = m + 1;
}
if (m <= n)
{
return m + "," + RAS(s, f, m, n);
}
else
{
return null;
}
}
To be continued。。。。。。