分析思路:类似于活动安排问题 。
应用贪心策略:将所有电影按照结束时间从小到大排序,第一步选择结束时间最早的那部电影,然后,每步都选择和上一步选中的电影不冲突且结束时间最早的电影。
选出一组最优解,与贪心解一步步进行比较,最后可以将最优解替换成贪心解。
时间复杂度:O(nlogn)
输入:
多组数据。每组数据开头是 n (n<=100),表示 共n场电影。接下来 n 行,每行两个整数 (均小于1000),表示异常电影的放映区间。n=0 数据结束输入。
输出:
对每组数据输出最多能看几部电影。
源码1:
#include <stdio.h>
int main()
{
int k = 0, n = 0;
int i, j, cout;
int a = 0, b = 0;
printf( "输入活动个数 n : " );
scanf( "%d", &n );
while ( n )
{
int T[11][11] = { 0 };
printf( "输入%d组数据,每组输入开始时间和结束时间:\n", n );
for ( k = 1; k <= n; k++ )
{
a = 0, b = 0;
scanf( "%d %d", &a, &b );
T[a][b] = 1;
}
int s = 0;
i = 0;
cout = 0;
j = i + 1;
while ( j < 11 && i < 11 )
{
if ( T[i][j] != 0 )
{
if ( i >= s )
{
s = j;
cout++;
i = j;
} else i++;
}
if ( T[i][j] == 0 )
{
++j;
}
if ( j == 11 && i != 11 )
{
i++;
j = i + 1;
}
}
printf( "最多%d个活动。\n", cout );
printf( "输入活动个数 n : " );
scanf( "%d", &n );
}
return 0;
}
测试数据:
(1)
6
0 2
1 3
2 3
2 4
3 6
5 6
(2)
7
1 5
3 5
4 7
6 8
8 9
8 10
9 10
分析及讨论:
- 有关算法逻辑结构的设计
- 用一个二维数组容纳这些活动,二维数组的行下标代表每个活动的开始时间;二维数组的列下标代表结束时间。通过在控制台输入活动个数n,然后输入n个活动将每个活动存入数组(例如,一个开始时间为2,结束时间为5的活动需要要被存在二维数组T[2][5]的位置,有几个这样的活动,就在相应的数组中存几。)
- 输入逻辑
printf( "输入活动个数 n : " ); scanf( "%d", &n ); while ( n ) { int T[101][101] = { 0 }; printf( "输入%d组数据,每组输入开始时间和结束时间:\n", n ); for ( k = 1; k <= n; k++ ) { a = 0, b = 0; scanf( "%d %d", &a, &b ); T[a][b] = 1; } }
先初始化一个二维数组,然后把每组数据存放在它应在的位置。
- 处理数据逻辑分析
int s = 0; //s代表前一个被选中的活动的结束时间 i = 0; //循环变量,行下标,代表每个活动的开始时间 cout = 0; //记录最多可以举办的活动的个数 j = i + 1; //循环变量,列下标,代表结束时间 while ( j < 11 && i < 11 ) //当遍历完整个二维数组时,退出循环 { if ( T[i][j] != 0 ) //当二维数组中有数据时,说明存在这样一个活动 { if ( i >= s ) //如果本活动的开始时间 < 一个被选中的活动的结束时间,则选中本活动 { s = j; //给下一次循环中的s赋值为本次活动的结束时间 cout++; //可观影场数+1 i = j; //移动活动开始时间的指针 } else i++; //如果i<s,说明本次活动不能被选中(本次活动开始时间<上一次活动的结束时间,产生冲突) } if ( T[i][j] = = 0 ) ++j; //没有这个时间段举行的活动,去检查下一个时间段 if ( j = = 11 && i != 11 ) //如果一直没有在i这个时间开始的活动,则寻找从i+1开始的活动 { i++; j = i + 1; } } printf( "最多%d个活动。\n", cout );
(2)有关时间复杂度的分析
如果是使用一般的贪心算法(例如本章的活动安排问题)去解决问题,需要进行一个时间复杂度为O(nlogn)的重排序,但是我设计的程序使用的是一个二维数组,从而避免了“重排序”,以空间换时间。由于程序最核心的部分是一个while-loop,并且最外层的循环是while(n),所以整个程序的时间复杂度为O(n2)。
(3)讨论
还有没有更加完美的方案,可以既节省空间的同时又节省时间?
其实还可以使用结构体来完成本题,虽然要对结构体进行一次快排,但是可以最大限度上节约空间。
struct node { int start; //存开始时间 int end; //存结束时间 } a[101];