Source code for pyflex.interval_scheduling
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Weighted interval scheduling implementation.
Adapted from
https://github.com/farazdagi/algorithms/blob/master/
weighted-interval-scheduling.py
:copyright:
Victor Farazdagi, 2013
Lion Krischer (krischer@geophysik.uni-muenchen.de), 2014
:license:
GNU General Public License, Version 3
(http://www.gnu.org/copyleft/gpl.html)
"""
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from future.builtins import * # NOQA
import collections
import bisect
def compute_previous_intervals(I):
"""
For every interval j, compute the rightmost mutually compatible interval
i, where i < j I is a sorted list of Interval objects (sorted by finish
time)
"""
# extract start and finish times
start = [i.left for i in I]
finish = [i.right for i in I]
p = []
for j in range(len(I)):
# rightmost interval f_i <= s_j
i = bisect.bisect_right(finish, start[j]) - 1
p.append(i)
return p
[docs]def schedule_weighted_intervals(I):
"""
Use dynamic algorithm to schedule weighted intervals
sorting is O(n log n),
finding p[1..n] is O(n log n),
finding OPT[1..n] is O(n),
selecting is O(n)
whole operation is dominated by O(n log n)
"""
# f_1 <= f_2 <= .. <= f_n
I.sort(key=lambda x: x.right)
p = compute_previous_intervals(I)
# compute OPTs iteratively in O(n), here we use DP
OPT = collections.defaultdict(int)
OPT[-1] = 0
OPT[0] = 0
for j in range(1, len(I)):
OPT[j] = max(I[j].weight + OPT[p[j]], OPT[j - 1])
# given OPT and p, find actual solution intervals in O(n)
O = []
def compute_solution(j):
if j >= 0: # will halt on OPT[-1]
if I[j].weight + OPT[p[j]] > OPT[j - 1]:
O.append(I[j])
compute_solution(p[j])
else:
compute_solution(j - 1)
compute_solution(len(I) - 1)
# resort, as our O is in reverse order (OPTIONAL)
O.sort(key=lambda x: x.right)
return O