4-1 会场安排问题
(一)题目
问题描述
假设在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的贪心算法进行安排。(这个问题实际上是著名的图着色问题。若将每个活动作为图的一个顶点,不相容活动间用边相连。使相邻顶点有着不同颜色的最小着色数,相当于要找的最少会场数。)
算法设计
对于给定的 n n n个待安排活动,计算使用最少会场的时间。
数据输入
由文件input.txt提供输入数据。第1行中有一个整数 n n n,表示有 n n n个待安排的活动。接下来的 n n n行中,每行有2个正整数,分别表示 n n n个待安排的活动的开始时间和结束时间。时间以0点开始的分钟计。
结果输出
将计算的最少会场数输出到文件output.txt。
(二)解答
方法思路
会场安排问题可以用贪心算法求解,采用结束时间最早的会场作为贪心选择
算法具体描述:
1)用数组s和f分别存储各活动的开始时间和结束时间,将s按非递减排序,该次序为各活动选择会场的次序;将f按非递减排序, 由于会场的结束时间由活动的结束时间决定,排序后的数组也是会场的结束时间点。
2)先为最早开始的活动开辟一个会场,此时会场的最早结束时间为该活动的结束时间,然后遍历剩下的活动,对于每个活动,判断当前最早结束的会场内是否仍有活动(即会场的最早结束时间大于该活动的开始时间),如果有,开辟一个新会场;如果没有,说明当前最早结束的会场能容纳当前的活动,更新会场的结束时间点,保证最早结束的会场最先开始下一个活动。
算法正确性证明:
1)贪心选择性质的证明
优解包含贪心选择的证明可用反证法,证明如下:
假设最优解不含贪心选择,即最优解 A A A的某个活动 a a a所选择的会场 r ’ r’ r’不是结束时间最早的会场 r r r,由于 r r r的结束时间小于 r ’ r’ r’, a a a能在 r r r中进行,说明 a a a必定能在 r r r中进行,因此用 r r r代替 r ’ r’ r’的结果 ( A − { r ′ } ) ∪ { r } (A-\{r'\})\cup\{r\} (A−{r′})∪{r} 仍是一个最优解,即最优解包含贪心选择,与假设矛盾。
2)最优子结构性质的证明
若 A A A是原问题 E E E的最优解,会场 r 1 r_1 r1安排的活动集合为 e e e,则 A ′ = A − { r 1 } A'=A-\{r_1\} A′=A−{r1}是子问题 E ′ = E − e E'=E-e E′=E−e的最优解,该命题的证明可用反证法,证明如下:
假设 B ′ B' B′是子问题 E ′ E' E′的更优解, B ′ B' B′比 A ′ A' A′所需的会场数更少,由于 E ′ E' E′与 e e e不相容,新开辟一个会场 r r r容纳活动集合 e e e对 B ′ B' B′无影响,那么 B ′ ∪ { r } B'\cup\{r\} B′∪{r}是原问题的更优解,与假设矛盾。
综上,会场安排问题可用贪心算法求解,且将结束时间最早的会场为贪心选择能得到最优解。
举例
设有4个活动,每个活动的开始和结束时间分别为{1, 6}, {4, 8}, {9, 10}, {7, 18}
总共需要2个会场
源代码
#include <cstdio>
#include <iostream>
#include<fstream>
#include <algorithm>
using namespace std;
int main()
{
int n; //活动个数
int s[100]; //各活动开始时间
int f[100]; //各活动结束时间
int i, j; //i,j分别指向开始时间和结束时间
int ans; //结果
//文件输入
ifstream ifs;
ifs.open("G:\\algorithm\\data\\4_1_input.txt", ios::in);
ifs>>n;
for (int i = 1; i <= n; ++i)
{
ifs>>s[i]>>f[i];
}
ifs.close();
//排序
sort(s + 1, s + n + 1); //将各活动的开始时间按非递减排序,排序后的数组为各活动选择会场的次序
sort(f + 1, f + n + 1); //将各活动的结束时间按非递减排序,由于会场的结束时间由活动的结束时间决定,排序后的数组也是会场的结束时间点
//为最早开始的活动开辟一个会场,此时会场的最早结束时间为该活动的结束时间
j = 1;
ans = 1;
//遍历剩下的活动
for (int i = 2; i <= n; ++i)
{
//判断当前最早结束的会场内是否仍有活动
//如果有,开辟一个新会场
if (f[j] > s[i])
{
ans++;
}
//如果没有,说明当前最早结束的会场能容纳当前的活动,更新会场的结束时间点,保证最早结束的会场最先开始下一个活动
else
{
j++;
}
}
//文件输出
ofstream ofs;
ofs.open("G:\\algorithm\\data\\4_1output.txt", ios::out);
ofs<<ans<<endl;
ofs.close();
}
结果示例
输入:
输出:
(三)总结
复杂度分析:
排序函数sort()的时间复杂度为 O ( n l o g n ) \Omicron(nlogn) O(nlogn)
为除最早结束的活动外的活动选择会场的循环次数为 n − 1 n-1 n−1,时间复杂度为 O ( n ) \Omicron(n) O(n)文章来源:https://www.toymoban.com/news/detail-470326.html
因此,整个算法的时间复杂度为 O ( n l o g n ) \Omicron(nlogn) O(nlogn)文章来源地址https://www.toymoban.com/news/detail-470326.html
到了这里,关于算法分析与设计-会场安排问题(贪心)(通俗易懂,附源码和图解,含贪心选择性质和最优子结构性质的证明)(c++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!