restructure, slow security solution

This commit is contained in:
2018-01-30 02:02:02 -05:00
parent c9be15672c
commit c925681921
18 changed files with 284 additions and 57 deletions

42
asecbadge.py Normal file
View File

@@ -0,0 +1,42 @@
from collections import deque, defaultdict
from intset import IntSet
N, L, B = map(int, input().split())
S, D = map(int, input().split())
rooms = defaultdict(dict)
ALL = IntSet(1, B + 1)
NONE = IntSet()
for i in range(L):
a, b, x, y = map(int, input().split())
rooms[a][b] = IntSet(x, y + 1)
ranges = defaultdict(lambda: NONE)
ranges[S] = ALL
q = deque([S])
while q:
if len(ranges[D]) == B:
break
curr = q.pop()
# if curr == D:
# continue
for neighbor, r in rooms[curr].items():
old = ranges[neighbor]
new = ranges[neighbor] | ranges[curr] & r
if old != new:
# try:
# q.remove(neighbor)
# except ValueError:
# pass
q.append(neighbor)
ranges[neighbor] = new
print(len(ranges[D]))

42
asecbadge_back.py Normal file
View File

@@ -0,0 +1,42 @@
from collections import deque, defaultdict
from intset import IntSet
N, L, B = map(int, input().split())
S, D = map(int, input().split())
rooms = defaultdict(dict)
ALL = IntSet(1, B + 1)
NONE = IntSet()
for i in range(L):
a, b, x, y = map(int, input().split())
rooms[b][a] = IntSet(x, y + 1)
ranges = defaultdict(lambda: NONE)
ranges[D] = ALL
q = [D]
while q:
# if len(ranges[D]) == B:
# break
curr = q.pop(0)
# if curr == D:
# continue
for neighbor, r in rooms[curr].items():
old = ranges[neighbor]
new = ranges[neighbor] | (ranges[curr] & r)
if len(old) != len(new):
# try:
# q.remove(neighbor)
# except ValueError:
# pass
q.append(neighbor)
ranges[neighbor] = new
print(len(ranges[S]))

50
asecbadge_iter.py Normal file
View File

@@ -0,0 +1,50 @@
from collections import deque, defaultdict
N, L, B = map(int, input().split())
S, D = map(int, input().split())
rooms = defaultdict(dict)
bounds = set()
for _ in range(L):
a, b, x, y = map(int, input().split())
rooms[a][b] = x, y + 1
bounds.add(x)
bounds.add(y + 1)
total = 0
bounds = sorted(bounds)
def piecewise(seq):
it = iter(seq)
last = next(it)
for new in it:
yield last, new
last = new
for a, b in piecewise(bounds):
q = deque([S])
visited = [0] * L
while q:
curr = q.pop()
visited[curr - 1] = 1
nbors = rooms[curr].items()
if curr == D:
total += b - a
break
for n, (la, lb) in nbors:
if visited[n - 1]:
continue
if a >= la and b <= lb:
q.append(n)
print(total)

111
intset.py Normal file
View File

@@ -0,0 +1,111 @@
class IntSet:
def __init__(self, *bounds):
"""Bounds must be tuples of the form (a, b),
where integers a <= x < b are included in the set.
"""
if not bounds:
bounds = [0, 0]
self.bounds = list(bounds)
def simplify(self):
i = 0
while i < len(self.bounds) - 1:
if i % 2 == 0:
if self.bounds[i] >= self.bounds[i + 1]:
del self.bounds[i:i + 2]
else:
i += 1
else:
if self.bounds[i] >= self.bounds[i + 1]:
if self.bounds[i] >= self.bounds[i + 2]:
del self.bounds[i + 1:i + 3]
else:
del self.bounds[i:i + 2]
else:
i += 1
def __or__(self, other):
bounds = None
j = k = 0
while j < len(self.bounds) - 1 or k < len(other.bounds) - 1:
if k >= len(other.bounds) - 1:
a, b = self.bounds[j:j + 2]
j += 2
elif j >= len(self.bounds) - 1:
a, b = other.bounds[k:k + 2]
k += 2
elif self.bounds[j] < other.bounds[k]:
a, b = self.bounds[j:j + 2]
j += 2
else:
a, b = other.bounds[k:k + 2]
k += 2
if a >= b:
continue
if not bounds:
bounds = [a, b]
continue
e = bounds[-1]
if e >= a:
if e >= b:
continue
bounds[-1] = b
else:
bounds.append(a)
bounds.append(b)
if not bounds:
bounds = [0, 0]
new = IntSet()
new.bounds = bounds
return new
def __and__(self, other):
bounds = []
i = j = 0
while i < len(self.bounds) - 1 and j < len(other.bounds) - 1:
a, b = self.bounds[i:i + 2]
c, d = other.bounds[j:j + 2]
if b > c and a < d:
bounds.append(max(a, c))
bounds.append(min(b, d))
if b < d:
i += 2 # toss a b
else:
j += 2 # toss c d
new = IntSet()
new.bounds = bounds
new.simplify()
return new
def __eq__(self, other):
return self.bounds == other.bounds
def __iter__(self):
for a, b in self.pairs:
yield from range(a, b)
def __len__(self):
return sum(b - a if b > a else 0 for a, b in self.pairs)
def __lt__(self, other):
return len(self) < len(other)
@property
def pairs(self):
it = iter(self.bounds)
while True:
yield next(it), next(it)
def __repr__(self):
return 'U'.join('[{0},{1})'.format(a, b) for a, b in self.pairs)

4
make_and_test.py Normal file
View File

@@ -0,0 +1,4 @@
import subprocess
subprocess.call(['python', 'make_nonsense.py'])
subprocess.call(['python', 'icpc_test.py', 'asecbadge_multi.py', 'security', '5'])

22
make_nonsense.py Normal file
View File

@@ -0,0 +1,22 @@
from itertools import islice, permutations
from random import randint, sample
N, L, B = 1000, 5000, 100_000_000
S = D = 0
while S == D:
S, D = randint(1, N), randint(1, N)
pairs = sample(list(permutations(range(N), r=2)), L)
rows = []
for a, b in pairs:
x = randint(1, B)
y = randint(x, B)
rows.append((a, b, x, y))
with open('test/security/nonsense.in', 'w') as f:
f.writelines(' '.join(map(str, tup)) + '\n' for tup in [(N, L, B), (S, D)] + rows)
with open('test/security/nonsense.ans', 'w') as f:
f.write('27\n')

View File

@@ -1,57 +0,0 @@
##N, L, B = input().strip().split()
##S, D = input().strip().split()
class Range():
def __init__(self, ranges):
self.ranges = ranges
def __add__(self, other):
new_ranges = list(self.ranges)
for rang1 in other.ranges:
for i, rang2 in enumerate(new_ranges):
if rang1[0] <= rang2[0] and rang1[1] >= rang2[1]:
new_ranges[i] = rang1
break
if rang1[0] >= rang2[0] and rang1[1] <= rang2[1]:
break
if rang1[1] >= rang2[0]-1 and rang1[1] <= rang2[1]:
new_ranges[i] = (rang1[0], rang2[1])
break
if rang1[0] >= rang2[0] and rang1[0] <= rang2[1]+1:
new_ranges[i] = (rang2[0], rang1[1])
break
else:
new_ranges.append(rang1)
return Range(new_ranges)
def __mul__(self, other):
new_ranges = []
for rang1 in other.ranges:
cand = rang1
for rang2 in self.ranges:
if rang1[0] <= rang2[0] and rang1[1] >= rang2[1]:
cand = rand2
elif rang1[0] >= rang2[0] and rang1[1] <= rang2[1]:
pass
elif rang1[1] >= rang2[0] and rang1[1] <= rang2[1]:
cand (rang2[0], rang1[1])
elif rang1[0] >= rang2[0] and rang1[0] <= rang2[1]:
cand = (rang1[0], rang2[1])
else:
break
else:
new_ranges.append(cand)
return Range(new_ranges)
def __repr__(self):
return str(*self.ranges)
def __str__(self):
return str(self.ranges)
Range.INF = Range([(-float('inf'), float('inf'))])
a = Range.INF
b = Range([(3, 4)])
print(a+b)

View File

@@ -0,0 +1 @@
10

View File

@@ -0,0 +1,6 @@
3 4 10
1 3
1 3 1 5
1 2 6 10
2 3 6 10
3 2 6 10

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,5 @@
4 3 10
1 4
1 3 1 5
1 2 6 10
2 3 6 10