贪心算法,简单地说就是面对一系列选择的时候,所做出的选择都是对当前状态下的最优选择。但因为他只考虑当前情况,所以在大多数的情况下,他总是很难达到预期的目的。所以在刚接触这贪心的时候会觉得很简单,谁还不会贪了?但在实际的情况下不容易找到正确的贪心方法。
目录
贪心的基本要求
1.贪心选择性质
贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。
我认为这就是贪心算法最难的地方,一个题目你可能很快的想到一个贪心策略,但你不证明他的贪心选择性就无法证明你这个策略的正确性,而证明贪心选择性也是我觉得最头疼的地方。
2.最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。这跟动态规划的最优子结构是一样的,所以在一个题目满足贪心算法时,他也一定满足动态规划的条件。
3.贪心与动态规格的区别
贪心算法较为简便,效率更高,但求出的解不一定是整体最优解。动态规划通过求子问题的解构造原问题的解,相对更为复杂,但通过若干局部解的比较,去掉了次优解,得到的必定是整体最优解。
会场安排问题
假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的贪心算法进行安排。(这个问题实际上是著名的图着色问题。若将每一个活动作为图的一个顶点,不相容活动间用边相连。使相邻顶点着有不同颜色的最小着色数,相应于要找的最小会场数。) 对于给定的k个待安排的活动,计算使用最少会场的时间表。
Input
输入数据的第一行有1 个正整数k(k≤10000),表示有k个待安排的活动。接下来的k行中,每行有2个正整数,分别表示k个待安排的活动开始时间和结束时间。时间以0 点开始的分钟计。
Output
输出一个整数,表示最少会场数。
Sample Input
5
1 23
12 28
25 35
27 80
36 50
Sample Output
3
代码
代码有点简陋仅供参考
#include<bits/stdc++.h>
using namespace std;
struct A{
int start;
int end;
}a[999];
int book[999];
int room;
int roomend;
bool cmp(A a,A b)
{
if(a.start!=b.start)
return a.start<b.start;
else return a.end<b.end;
}
void f(int n)
{
int count=0;
while(count<n)
{
roomend=0;
for(int i=1;i<=n;i++)
{
if(book[i]==0&&a[i].start>=roomend)
{
roomend=a[i].end;
book[i]=1;
count++;
}
}
room++;
}
cout<<room;
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].start;
cin>>a[i].end;
}
sort(a+1,a+n+1,cmp);
f(n);
}
题解
这个题在刚做的时候就受到活动安排问题的影响,就认为先把一个会场安排尽量多的活动,然后再安排下一个会场,显然答案就是错误的。就是因为贪心选择性不正确,在这个题目我们要贪的不是要让每一个会场安排的活动个数尽量多,因为这对占时间短的活动太有利了导致时间有冲突,短活动浪费的会场太多,所以我们认为要贪的应该是尽量让每个会场时间排版的尽量满。
所以首先我们要对活动进行排序,这次不是按照结束时间了,而是开始时间越早排在越前面,如果两个活动时间相同,则结束时间越早的排在越前面始时间最早和持续时间最短的优先安排会场,并记录会场号,其余活动的开始时间大于或等于已安排活动的结束时间的安排在同一会若某活动的开始时间小于已经安排了会场的活动的结束时间,则安排在另一会场,记录会场号,依次循环,直到所有活动均被安排。