POJ 4151/北大百练 4151 电影节 题解(两种方法)贪心算法基础

POJ4151 电影节

总时间限制:
1000ms
内存限制:
65536kB

描述:
大学生电影节在北大举办! 这天,在北大各地放了多部电影,给定每部电影的放映时间区间,区间重叠的电影不可能同时看(端点可以重合),问李雷最多可以看多少部电影。
输入:
多组数据。每组数据开头是n(n<=100),表示共n场电影。
接下来n行,每行两个整数(0到1000之间),表示一场电影的放映区间
n=0则数据结束
输出:
对每组数据输出最多能看几部电影
样例输入:
8
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
0
样例输出:
3
来源:
Guo Wei

题意分析:

由题目可知,要尽量看更多的电影,那么策略就是通过对电影时间进行某一种排序后,再进行贪心策略

下面给出两种方法:

方法一:

对电影结束时间进行从早到晚的排序,然后尽量选取结束早的电影看,以节省时间看后面的更多的电影。具体的操作方法是:对按结束时间排序后的电影从早到晚一个个遍历,若当前遍历到的这部电影的结束时间早于下一部电影的开始时间,则sum++(sum初始化为1,因为显然最少可以看一部电影),若当前遍历到的这部电影的结束时间完于下一部电影的开始时间,则看当前这部,不看下一部电影了(原因:对于重合的两场电影,当然选择结束早的,为后面留下更多的时间,这就是一种贪心思想)。

AC代码:

// An highlighted block
#include<bits/stdc++.h>
using namespace std;


struct node
{
    int begin,end;//记录开始时间和结束时间
}a[105];


int cmp(node a,node b)
{
    return a.end<b.end;//按结束时间由小到大排序
}


int main()
{
    int t;
    while((cin>>t)&&(t!=0))//数据组数
    {
        for(int i=0;i<t;i++)
        {
            scanf("%d%d",&a[i].begin,&a[i].end);//依次输入数据
        }
        sort(a,a+t,cmp);//排序
        int sum=1;//最少看的电影书肯定是1
        int js;//表示结束时间
        js=a[0].end;
        for(int i=1;i<t;i++)//依次遍历
        {
            if(a[i].begin>=js)//如果下一场开始的时间在这一场结束时间之后,就满足要求
            {
                js=a[i].end;//更新结束时间的值
                sum++;//可以看电影的个数+1
            }
        }
        printf("%d\n",sum);
    }
}

方法二:

自己瞎想出来的野路子,没有第一种简洁,但方法还是挺有意思滴而且没有用到c++的知识(纯c实现的)。

大体思路是:利用a[x]=y储存开始时间和结束时间(x是开始时间,y为结束时间)。由于存在同一个开始时间对应着两场结束时间不一样的电影的情况,就要对这种情况下的电影进行取舍,和方法一的贪心策略一样,当然选择结束时间早的(如何选择时间少的呢,不妨让每次输入进来的x,y时,让a[x]与y对比,若a[x]>y,则将y赋值给a[x]以更新a[x])。同时每次输入一个x时,让q[x]++(在这操作前要对q[1005]全部初始化为0,以记录出现过哪些x)。

然后再搞一个rem[1005]数组,以记录x,记录方法为rem[1]=x1(x1为输入的x中第一小的x) rem[2]=x2 …………以此类推下去。

然后就剩代码中这部的理解了:

// An highlighted block
for(int i=1; i<=cnt-1; i++)//cnt是一共有几个不同的 x
        {
            if(a[rem[i]]<=rem[i+1])//情况1下面画图来解释
            {
                sum++;
            }
            else if(a[rem[i]]>=a[rem[i+1]]&&rem[i]<=rem[i+1])//情况2
            {
                continue;
            }
            else if(a[rem[i]]>=rem[i+1])//情况3
            {
                a[rem[i+1]]=a[rem[i]];
            }
        }
        printf("%d\n",sum);

情况一:(上面的线是第i场电影的时间长度线 ,下面的是i+1场的时间长度线)

《POJ 4151/北大百练 4151 电影节 题解(两种方法)贪心算法基础》

情况二:

《POJ 4151/北大百练 4151 电影节 题解(两种方法)贪心算法基础》

情况三

《POJ 4151/北大百练 4151 电影节 题解(两种方法)贪心算法基础》

下面是这个方法的AC完整代码:

// An highlighted block
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <algorithm>
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        int a[1005];
        int rem[1005]= {0};
        for(int i=0; i<=1004; i++)
        {
            a[i]=9999;
        }
        int x,y;
        int sum=1;
        int q[1005]= {0};
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d",&x,&y);
            if(x==y){sum++;}
            q[x]++;
            if(a[x]>y)
            {
                a[x]=y;
            }
        }
        int cnt=0;
        for(int i=0; i<=1000; i++)
        {
            if(q[i]!=0)
            {
                cnt++;
                rem[cnt]=i;
            }
        }
        for(int i=1; i<=cnt-1; i++)
        {
            if(a[rem[i]]<=rem[i+1])
            {
                sum++;
            }
            else if(a[rem[i]]>=a[rem[i+1]]&&rem[i]<=rem[i+1])
            {
                continue;
            }
            else if(a[rem[i]]>=rem[i+1])
            {
                a[rem[i+1]]=a[rem[i]];
            }
        }
        printf("%d\n",sum);

    }
    return 0;
}

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/qq_43553133/article/details/84945977
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞