算法讲解

会场安排问题

2017-11-25  本文已影响0人  我没有三颗心脏

问题描述:

假设要在足够多的会场里安排一批活动,并希望使用尽可能少的会场。设计一个有效的贪心算法进行安排(这个问题实际上是著名的图着色问题。若将每一个活动作为图的一个顶点,不相容活动间用边相连。使相邻顶点着有不同颜色的最小着色数,相应于要找的最小会场数)。

来换一个描述

为了能够更加生动说明问题的整个过程,所以换一个类似的描述来契合《算法图解》一书中的描述。

你没法让这些课都在这间教室上,因为有些课的上课时间有冲突。

你希望这间教室上尽可能多的课。如何选出尽可能多且时间不冲突的课程呢?

这个问题似乎很难,但算法却简单得让人吃惊。具体做法如下:

重复这样做就能找出答案!下面来试一试。美术课的结束时间最早,为10:00 a.m,因此它就是第一堂课。

接下来的课必须在10:00 a.m后开始,且结束得最早。

英语课不行,因为它的时间与美术课冲突,但数学课满足条件。最后,计算机课与数学课的时间是冲突的,但音乐课可以。

因此将在这间教室上如下三堂课。

贪婪算法很简单:每步都采取最优的做法。在这个示例中,你每次都选择结束最早的课。用专业术语说,就是你每步都选择局部最优解,最终得到的就是全局最优解。听上去有些神奇,但对于这个调度问题上,上述的简单算法找到的就是最优解。

数据输入

第一行有1个正整数k,表示有k个待安排的活动。接下来的k行中,每行有两个正整数,分别表示k个待安排的活动开始时间和活动结束时间。时间以0点开始的分钟计。

由于问题定义上有些纰漏,但通常,我们认为如果上一个活动在t时间结束,下一个活动最早应该在t+1时间开始(上述问题有一定出入)

代码实现

考虑到用户输入并不会按照开始的时间或者结束的时间严格输入,所以我们自己或许要加一个排序算法,这对我们自己遍历也会提供方便:

private static int meeting_problem(int[] startTime,int[] endTime){
    //一组活动数据的最优解
    int maxresult = 1;
    //冒泡排序,对startTime和endTime数据进行排序
    for (int i = 0; i < endTime.length-1; i++) {
        boolean canBreak = true;
        for (int j = 1; j < endTime.length - i; j++) {
            if (endTime[j-1] > endTime[j]) {
                int temp = endTime[j - 1];
                endTime[j-1] = endTime[j];
                endTime[j] = temp;

                int temp2 = startTime[j - 1];
                startTime[j-1] = startTime[j];
                startTime[j] = temp2;
                canBreak = false;
            }
        }
        if (canBreak) {
            break;
        }
    }
    // 记录上一次活动的结束时间
    int key = endTime[0];
    for (int i = 1; i < endTime.length; i++) {
        // 如果活动的开始时间能够大于上一次活动的结束时间
        if (startTime[i] - key >= 1){
            //计数+1
            maxresult ++;
            //保存结束时间
            key = endTime[i];
        }
    }
    return maxresult;
}

结合输入的代码:

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int num = scanner.nextInt();
    int[] results = new int[num];
    for (int i = 0; i < num; i++) {
        int a = scanner.nextInt();
        int[] startTimes = new int[a];
        int[] endTimes = new int[a];
        for (int j = 0; j < a; j++) {
            startTimes[j] = scanner.nextInt();
            endTimes[j] = scanner.nextInt();
        }
        results[i] = (meeting_problem(startTimes, endTimes));
    }
    for (Integer result:results) {
        System.out.println(result);
    }
}

这里直接引用了 黑白咖 的文章:http://www.jianshu.com/p/0ce92abe862d 中的代码。

另外一种思路

我们也可以通过找最大重叠数来完成,这里不符合贪心策略,所以就不作深入研究。

欢迎转载,转载请注明出处!
简书ID:@我没有三颗心脏
github:wmyskxz
欢迎关注公众微信号:wmyskxz_javaweb
分享自己的Java Web学习之路以及各种Java学习资料

上一篇下一篇

猜你喜欢

热点阅读