【贪心算法】大学生观影问题

分析思路:类似于活动安排问题 。

应用贪心策略:将所有电影按照结束时间从小到大排序,第一步选择结束时间最早的那部电影,然后,每步都选择和上一步选中的电影不冲突且结束时间最早的电影。

选出一组最优解,与贪心解一步步进行比较,最后可以将最优解替换成贪心解。

时间复杂度: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

分析及讨论:

  1. 有关算法逻辑结构的设计
  • 用一个二维数组容纳这些活动,二维数组的行下标代表每个活动的开始时间;二维数组的列下标代表结束时间。通过在控制台输入活动个数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];
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值