Sunday, April 19, 2020

USACO Moo Particle version 2

Moop Version 2

USACO 2020 US Open Contest, Silver

Problem 3. The Moo Particle

Version 2

In [1]:
# SAMPLE INPUT
# 4
# 1 0
# 0 1
# -1 0
# 0 -1
In [2]:
fin = open ('moop.in', 'r')
fout = open ('moop.out', 'w')
# N = particles

N = int(fin.readline().strip())
print("N",N)
N 4
In [3]:
moo = []  # EACH PARTICLE HAS A DISTINCT SPIN
for i in range(N):
    x,y = map(int,fin.readline().split())
    moo.append((x,y))
    
moo.sort(reverse=True)
print(moo)
[(1, 0), (0, 1), (0, -1), (-1, 0)]
In [4]:
# Find the Pareto Frontier, the points that are not dominated by any other points
# i.e. no points above or to the right
a,b = moo[0]
# the first point has largest X, so it is on the frontier
frontier = [(a,b)]

# As the pareto particles are identified 
# keep track of the minimum Y value observed among subordinate particles that 
# are dominated by the current pareto particle
miny = b
minyList = []

for x,y in moo[1:]:
    if x<=a and y<=b:
        if y<miny:
            miny=y
        continue
    else:
        frontier.append((x,y))
        minyList.append(miny)
        a=x
        b=y
        miny=b
minyList.append(miny)

# the list of pareto particles, ordered by descending X value
print("frontier",frontier)
# list of minimum Y values associated with each pareto particle
print("minyList",minyList)     
frontier [(1, 0), (0, 1)]
minyList [0, -1]
In [5]:
# we need to scan the pareto list in order of increasing X value
# this is the reverse of the current list
# We want to examine each dominant point to see if it shares any subordinate 
# points with the dominant points before it on the list (with lower X value)
# 
# Here we reverse the list and take of the first point; we can begin with the second
# point and check if it shares with the first point.
rfrontier = frontier[len(frontier)-2::-1]
print("rfrontier",rfrontier)
rfrontier [(1, 0)]
In [6]:
# We need to reverse the minimum Y values associated with the pareto points
# The last point on the reversed list can be dropped because we begin by 
# comparing the first minimum Y value with the second pareto point (so the last 
# Y value will never be used).
# Also, we need to carry forward the global minimum Y value observed, since this
# may be a subordinate point for all pareto points going forward in the scan
ry = []
lasty = 999999999
for i in minyList[:0:-1]:
    if i < lasty:
        lasty = i
    ry.append(lasty)
print("ry",ry)
ry [-1]
In [7]:
# Now we can scan the pareto points and count the connected components.
# If the next pareto point in the scan has a higher Y value than the
# minimum Y value associated with previous points, then there is a shared
# subordinate point and the point is not counted.
count = 1
for pair, y in zip(rfrontier,ry):
    a,b = pair
    if b<y:
        count+=1
        
print(count)
fout.write(str(count)+"\n")
fout.close()
1

This code passes all test cases in analysis mode. The official solution recommends looking at the particles as nodes in a graph, with edges indicating that the particles can interact. Then this becomes a UNION-FIND problem and the answer is the number of connected components. Unfortunately, I took a more complicated approach, but it was still possible to solve the problem with a sub-optimal approach.