活动选择问题描述:
存在一个教室,有下面若干个活动需要安排在一天进行,活动之间不能重叠,如何安排活动使活动的数量最多?
活动序号 1 2 3 4 5 6 7 8 9 10 11 (活动已经按结束时间排好)
开始时间 1 3 0 5 3 5 6 8 8 2 12
结束时间 4 5 6 7 9 9 1011 12 14 16
贪心解题思路:
贪心的核心在于局部最优解,在本题中,要想使活动数量最多,最优解即选择结束时间最早的活动,预留出了最大的空间给后面的活动来进行所以我们首先把活动按结束时间来进行排序,这样省去了寻找的麻烦,方便了查找。
因为活动已经按照结束时间排序,按照选择结束时间最早活动,所以第一个活动选择编号为1的活动,为了方便代码的实现,所以加了序号为0的活动。
活动选择贪心代码实现:
#define NUM 11 //活动数量
//活动开始时间数组
int start[NUM + 1] = { 0,1,3,0,5,3,5,6,8,8,2,12 };
//活动结束时间数组
int end[NUM + 1] = { 0,4,5,6,7,9,9,10,11,12,14,16 };
//活动选择问题
vector<int> ActivitySelectorActivity(int *s, int *e)
{
int i = 1, j;
vector<int> resV; //用于存储结果
resV.push_back(1); //默认把结束时间最早的活动加入最终结果,活动时间已经排好,所以默认把1加入
for (j = 2; j <= NUM + 1; j++)
{
if (s[j] >= e[i])
{
resV.push_back(j); //把下一个最早结束的活动加入结果
i = j; //比较对象改成排在最后的活动
}
}
return resV;
}
//打印结果
void OutputResult(vector<int> resV)
{
int i;
for (i = 0; i != resV.size(); ++i)
{
cout << resV[i] << "\t";
}
cout << endl;
}
时间复杂度:
排除排序活动的时间不谈,活动选择主函数中进行了一层循环,所以时间复杂度为O(n)。
小船过河问题描述:
有若干人需要过河,只有一条船,每个人划船的耗时不同,每次两个人划船,耗时为两人中较长的一个的,划船过去后需要人划船回来,问如何设计让所有人过河且耗时最短?
贪心解题思路:
假设存在最少4个人abcd需要渡河,耗时a<b<c<d,这时就有两种最快方案:
(1)让a,b先渡河,a回来并担当船夫不断拉c和d过河,这样船划回来的时间最短,耗时为2*a[0]+a[n-2]+a[n-1]
(2)让a,b先渡河,a回来,然后c,d渡河,然后c回来,最后一起渡河,耗时为a[0]+2*a[1]+a[n-1]
两种情况的优劣取决于abcd的耗时,所以本题就分解为局部求最优解。
小船过河代码实现:
int a[1000]; //人数N的范围为1<=N<=1000,数组a表示人的集合
//小船过河(贪心)
int CrossRiver(int t,int num)
{
int sum = 0; //渡河总时间
int n = num; //渡河总人数
while (t--) //共几组人
{
for (int i = 0; i < n; i++)
{
cin >> a[i]; //输入每个人渡河时间
}
//每四个人局部计算最优解
while (n>3)
{
sum += min(a[1] + a[0] + a[n - 1] + a[1], a[n - 1] + a[0] + a[n - 2] + a[0]);
n -= 2;
}
if (n==3)
{
sum += a[0] + a[1] + a[2];
}
else if (n == 2)
{
sum += a[1];
}
else
{
sum += a[0];
}
return sum;
}
}