我正在使用Django从头开始编写基本的计划程序,但是在这种情况下,请忽略框架和语言本身。
问题:
给定n个事件,请显示一个事件与其他事件的全部冲突。假定给定的事件按start_time
排序。
其他要求: 如果事件A与事件B发生冲突,则该冲突必须显示两次-一次提及所有与事件A的冲突,另一次提及所有与事件B的冲突。
我曾尝试遵循一些解决方案来解决与此相关的问题,但是所涉及的算法并未输出所有冲突,也不满足附加要求。
到目前为止,这就是我现在所拥有的。假设Event
是包含字段start_time
和end_time
的组合数据结构。
def overlap(interval_1: Event, interval_2: Event):
if interval_1.start_time < interval_2.end_time and interval_2.start_time < interval_1.end_time:
return True
return False
def list_conflicts(events: List[Event]):
results = defaultdict(list)
for i in range(len(events)):
event_selected = events[i]
for e in itertools.islice(events, i):
if overlap(event_selected, e):
results[e].append(event_selected)
results[event_selected].append(e)
return results
答案 0 :(得分:0)
经过十几次尝试使它变得更好之后,我现在需要睡觉。
list_conflicts_1
是原始实现,而list_conflicts_2
是hyde's proposal.
好:
坏:
附加说明:
(id, id)
元组列表作为结果输出。使用的内存更少,但是结果至少比使用字典慢2倍。import functools
import itertools
import operator
import random
import enum
import time
from collections import defaultdict
from datetime import datetime
from typing import Tuple, DefaultDict, List, Any, Set
import perfplot
import numpy
def overlap(interval_1: Tuple[int, int, int], interval_2: Tuple[int, int, int]) -> bool:
return interval_1[1] < interval_2[2] and interval_2[1] < interval_1[2]
def list_conflicts_1(events: List[Tuple[int, int, int]]) -> DefaultDict[Any, List]:
results = defaultdict(list)
for i in range(len(events)):
event_selected = events[i]
for e in itertools.islice(events, i):
if overlap(event_selected, e) and (e[0], event_selected[0]) not in results:
results[e[0]].append(event_selected[0])
results[event_selected[0]].append(e[0])
return results
class Token(enum.Enum):
start = 0
stop = 1
def list_conflicts_2(events: List[Tuple[int, int, int]]) -> DefaultDict[Any, List]:
results = defaultdict(list)
time_list = sorted(
functools.reduce(operator.iconcat,
list(([(Token.start, e_id, start), (Token.stop, e_id, end)] for e_id, start, end in events)), []
), key=lambda a: a[2])
stack = []
for token, t_id, _ in time_list:
if token == Token.start:
stack.append(t_id)
if len(stack) > 1:
for i in itertools.islice(stack, len(stack) - 1):
results[i].append(t_id)
results[t_id].append(i)
if token == Token.stop and t_id in stack:
stack.remove(t_id)
return results
def create_t_random(a, b):
return random.randrange(a, b)
def create_t_precise(x):
return x
# This portion is a sanity test: Can be ignored
sanity_test_case = sorted([
(1, create_t_precise(4), create_t_precise(7)),
(2, create_t_precise(5), create_t_precise(8)),
(3, create_t_precise(9), create_t_precise(12)),
(4, create_t_precise(13), create_t_precise(14)),
(5, create_t_precise(9), create_t_precise(15)),
(6, create_t_precise(10), create_t_precise(17)),
], key=lambda x: x[1])
assert (list_conflicts_1(sanity_test_case) == list_conflicts_2(sanity_test_case))
def generate_bcs(n):
return sorted(((i+1, i, i+1) for i in range(n)), key=lambda a: a[1])
def generate_wcs(n):
return sorted(((i+1, 1, 1000) for i in range(n)), key=lambda a: a[1])
# Best case scenario
perfplot.show(
setup=generate_bcs,
kernels=[list_conflicts_1, list_conflicts_2],
n_range=[2 ** k for k in range(14)],
logx=True,
logy=True,
xlabel='num lists',
equality_check=lambda x, y: x == y
)
# Worst case scenario
perfplot.show(
setup=generate_wcs,
kernels=[list_conflicts_1, list_conflicts_2],
n_range=[2 ** k for k in range(14)],
logx=True,
logy=True,
xlabel='num lists',
equality_check=lambda x, y: x == y
)
结果:
最佳情况(无重叠)(BCS):
BCS下的 list_conflicts_2
属性:
最坏情况(所有重叠)(WCS):
WCS下的 list_conflicts_2
属性: