当前位置: 首页 > 知识库问答 >
问题:

求解学生活动选择问题的最大班级数算法

沈树
2023-03-14

输入格式

  • 第一行包含一个整数n,它给出了当天提供的主题数量。
  • 接下来的n行包含主题名称(是一个字符串),然后是该主题的24小时格式的开始和结束时间:hh:mm

例如:Maths 10:00 11:00
注意:时间是以24小时的格式给出的,主题名称之间没有空格。

4
Maths 16:00 18:00
ComputerScience 12:00 13:00
Physics 12:30 14:00
Chemistry 14:00 16:30
2

解释
计算机科学开始最早,结束最早,所以我们先取。在那之后,我们不能选物理,因为它在计算机科学结束之前就开始了。所以我们要上下一节课,也就是化学。但是化学之后我们不能上数学课,因为数学课在化学课结束之前就开始了。所以我们一天最多可以安排两节课。

以下是我的解决方案,但我没有得到正确的答案:

private void getMaxClass(String input) {

    Map<String, Long> classTime = new LinkedHashMap<>();
    Map<String, List<String>> timeMap = new LinkedHashMap<>();
    String[] split = input.split(" ");
    String subject = split[0];
    String StartTime = split[1];
    String endTime = split[2];
    List<String> lvalue = new ArrayList<>();
    lvalue.add(StartTime);
    lvalue.add(endTime);
    timeMap.put(subject, lvalue);
    long difference = FineDifferenceInTime(StartTime, endTime);
    classTime.put(subject, difference);
    int count = 0;
    Date date1 = null;
    Date date2 = null;
    Map<String, Long> sortedByValueDesc = classTime.entrySet().stream()
            .sorted(Map.Entry.<String, Long>comparingByValue())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
    for (Map.Entry<String, Long> entry : sortedByValueDesc.entrySet()) {
        String sub = entry.getKey();
        List<String> startEnd = timeMap.get(sub);
        Date dateBefore = null;
        Date dateAfter = null;
        SimpleDateFormat format = new SimpleDateFormat("HH:mm");
        try {
            dateBefore = format.parse(startEnd.get(0));
            dateAfter = format.parse(startEnd.get(1));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        if (count == 0) {
            count++;
            try {
                date1 = format.parse(startEnd.get(0));
                date2 = format.parse(startEnd.get(1));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        if (dateBefore.after(date1) && dateBefore.before(date2)) {
            timeMap.remove(sub);
        }
    }
    System.out.println(timeMap.size());
}

共有1个答案

傅鸿波
2023-03-14

这在文献中被称为区间调度问题。有很多方法来解决它,但由于它是NP完全的(因为有一个多项式约简从VC),你必须探索所有的组合。

贪婪算法确实存在(你的算法和@Priyankadeshmukh的解决方案也是如此),但它们不能保证所有问题的精确解。

下面的解决方案是一个简单的树搜索:在每个级别上,我们决定是否选择一门给定的课程,然后继续决定下一门课程。

class StudentClass {
    public int _start;
    public int _end;
    public String _name;
    public StudentClass(String name, int start, int end) {
        _name = name;
        _start = start;
        _end = end;
    }
    public boolean overlapsWith(StudentClass other) {
        return _start < other._end && _end > other._start;
    }
    public String toString() {
        return "[" + _start + " - " + _end + "] " + _name;
    }
}

有一些类来表示一天中的时间,但是它们的语法/实例化有点烦人/冗长--尽管可以改进这个答案!我的Java也很生疏,请随时纠正我:-)

Schedule类有一个getmaxschedule(),它返回问题的解决方案--学生可以上的最大类数是多少,这样它们就不会重叠了?

有几种方法来优化它,但我让它保持原样,因为我相信它更容易被理解。

public class Schedule {

    List<StudentClass> _classes = new LinkedList<>();

    public void addClass(String name, int startTime, int endTime) {
        _classes.add(new StudentClass(name, startTime, endTime));
    }

    private int getMaxSchedule(int index, Collection<StudentClass> html" target="_blank">selected) {
        // check if we reached the end of the array
        if (index >= _classes.size()) {
            return 0;
        }

        StudentClass current = _classes.get(index);

        // check if taking this class doesn't conflict with the
        // previously-selected set of classes
        boolean canTakeThisClass = true;
        for (StudentClass other : selected) {
            if (current.overlapsWith(other)) {
                canTakeThisClass = false;
                break;
            }
        }

        // check best schedule if we don't take this class
        int best = getMaxSchedule(index + 1, selected);

        // check best schedule if we take this class (if such is possible)
        if (canTakeThisClass) {
            selected.add(current);
            best = Math.max(best, 1 + getMaxSchedule(index + 1, selected));
            selected.remove(current);
        }

        return best;
    }

    public int getMaxSchedule() {
        Collection<StudentClass> selected = new ArrayList<>();
        return getMaxSchedule(0, selected);
    }
}
public static void main(String[] args) {
    Schedule s = new Schedule();
    s.addClass("Maths", 1600, 1800);
    s.addClass("Computer Science", 1200, 1300);
    s.addClass("Physics", 1230, 1400);
    s.addClass("Chemistry", 1400, 1630);
    System.out.println("maximum classes: " + s.getMaxSchedule());
}
 类似资料:
  • 我想从db中获取学生列表,他们在每个班级中使用学生姓名获得最大人数。使用MySQL数据库。 我有如下表格,如学生、班级、成绩(不同年份的成绩) 表结构学生(student_id,student_name,class_id,地址),班级(class_id,class_name),结果(result_id,student_id,年份,分数) 我需要这样的清单

  • 主要内容:10、你有什么业余爱好?1、 你对学生会是怎么看的?对于学生会你有什么想法? 学生会是联系学校和同学的纽带,是一个为同学服务的机构,也是一个锻炼自我展现自我的平台。进入学生会可以更好的发挥我的特长,为同学服务,并在工作中发现我的不足,提高自己充实自己。 2、你为什么要加入XX部门?(判断沟通能力和口才) 你对XX部了解有多少? 回答这个问题时,一定要积极正面,如想要使自己能有更好的发展空间,希望能在相关领域中有所发展,希

  • 问题内容: 如何选择类似的课程? 我已经试过了: 问题答案: 正如Zepplock所说,实际上是单个属性中的两个类:和。该空格不是类名的一部分;它充当分隔符。 这三个选择器都将与之匹配: 最后一个选择器仅拾取该元素,因为它同时具有 两个 类。 你 从来没有 链接类选择的时候,甚至没有像这样包括空间: 这样可以选择包含在单独元素中的元素。

  • 问题内容: 我在表中有三列:id,街道名称,计数。对于某些ID,不只是一个街道名称。Count告诉将每条街道分配给ID的频率。我怎样才能只获得编号最高的ID和街道名称。 表格示例: 结果应该是这样的: 提前致谢! 问题答案: 您没有指定正在使用的数据库,但是应该可以使用以下数据库: 请参阅带有演示的SQL Fiddle 。注意,您将必须使用MySQL的反引号或数据库使用的任何字符来转义保留字来转义

  • 我在开始新活动时遇到了一些问题。在我的应用程序中,我设置了侦听意图的广播接收器(屏幕关闭)。当屏幕关闭时,我的应用程序应该开始新活动(当然在某些情况下。我没有制作垃圾邮件应用程序)。但有时不是。 我在清单中声明了活动“singleTop”,所以我也重写了“onNewIntent”方法。(我认为这很重要)但事情是这样的。 当手机进入睡眠状态并且满足某些条件时,屏幕上会出现两个图标(“我的活动”)。我

  • 问题内容: 我有一个希望很简单的MySQL查询问题,在深夜使我难以理解。我正在尝试执行SELECT,该SELECT计算一组数据(订单)的实例数量,并通过在订单本身上方几层的父级中存在的值对这些实例进行分组。 例如: 我正在寻找的是以下附近的东西: SELECT count(orders.id),categoryId来自订单,类别(1,2,3)中的WHERE order.customer_id,GR