# Homework 3 (HW3) ###### tags: `2020pdsa` Due: 10/30 21:00 Judge Open: 10/19 [toc] ## Version Python: 3.8.5 (Note: no numpy) Java: openjdk14 (https://openjdk.java.net/projects/jdk/14/) Platform: Debian ## Our Judge https://140.112.183.224:13000 Grading Status: * AC: ACcepted * TLE: Time Limit Excess * WA: Wrong Answer * RE: Runtime Error (Mostly your program raise some error unexpectly) Memory: 2G Handin the file with utf-8 encoding if there are 中文 words inside your code (including comments). ### Template Download https://cool.ntu.edu.tw/courses/3501/files/folder/Homework_Template # HW3-1 Restaurants Given a list of restaurants and then filter it. The attributes of a restaurant are four integers in this order: `id` `rate` `price` `distance`, where the `rate` has only five possible values: 1,2,3,4 or 5. To filter the list, I will give you `min_price`, `max_price`, `min_rate` then you return the resturants' id that meets the condition: `min_price <= price <= max_price` and `rate >= min_rate`. The output is an integer list, which should be in the increasing order of distance; if the distance equals, order the restaurant ids from the largest to the smallest. In case6, we want you to implement two comparators for the class Restaurant. One is the natural order, which should be implemented by the comparable interface (java), the other one is a comparator object/method (called `Comparator1`). For example, there is a list of restaurants, `r :list[Restaurant]`. `sorted(r)` will sort the array by calling the natural comparator. Similariary `sorted(r, cmp=Compparator1)` will sort the list by `Comparator1`. See more details in the template session. The natural comparator should order the restaurants by the formula `distance * price / rate`, if the value is the same, keep the same order as input. The `comparator1` should order the restaurants by the rate in increasing order, distance in increasing order (if tied), and id in decreasing order (if tied again). ## Hint * Sorting * The concept of argsort * Minimize the number of iterations (You should do as minimal steps as you can) * You will get lots of TLE if you iterate the restaurants when unnecessary. * Implement comparator ![](https://i.imgur.com/kLDopcJ.png) * The above figure shows you should not waste time on P and Q region * Data imblancing(e.g. number of rate1 >> rate5) will make `P >> M` when query `min_rate = 5` * Binary sort * Restaurants only created **one time**, but `filter` may called about 1000 times. * `int a=13,b=3; float c=a/b;` `c==4` will be true because `a/b` is interger ## Template ``` python import functools from typing import List class Restaurant(object): def __init__(self, id :int, rate :int, price :int, distance :int): pass def getID(self) -> int: return 0 def __lt__(self, b) -> bool: """ The natural comparator of Restaurant The comparator should compare the restaurants by the value calculated from the formula `distance * price / rate` and return True if the value of `self` is lower than `b` If the value is the same, keep the same order as input. """ return True @staticmethod def comparator1(a, b) -> int: """ Compare two restaurants by restaurant object Order the restaurants by the rate in increasing order, distance in increasing order (if tied),and id in decreasing order (if tied again). Parameters: a(Restaurant): The restaurant object b(Restaurant): The restaurant object Returns: result(int): -1 for restaurant a has smaller order, 1 for restaurant b has smaller order, 0 for equal. """ return 0 class Restaurants(object): def __init__(self, restaurants :List[Restaurant]): pass def filter(self, min_price: int, max_price :int, min_rate: int) -> List[int]: """ Filter the restaurants, output the list of restaurant id that meet the condition. Output the list in in the increasing order of distance; If the distance is the same, order the restaurant ids from the highest to the lowest. Returns: restaurants (List[int]): The list of restaurant id. """ return [] if __name__ == "__main__": rests = [ # id, rate, price, distance Restaurant(20, 1, 20, 12), Restaurant(15, 3, 19, 11), Restaurant(19, 4, 19, 12), Restaurant(18, 5, 20, 11), ] r = Restaurants(rests) print(r.filter(0, 25, 3)) print(r.filter(0, 25, 4)) print(r.filter(0, 20, 1)) print(r.filter(0, 10, 1)) print(r.filter(0, 19, 1)) print(r.filter(19, 19, 3)) # case6 rests = [ # id, rate, price, distance Restaurant(3, 2, 3, 8), Restaurant(0, 2, 4, 6), Restaurant(2, 4, 5, 12), Restaurant(1, 5, 6, 11), ] print([i.getID() for i in sorted(rests)]) print([i.getID() for i in sorted(rests, key=functools.cmp_to_key(Restaurant.comparator1))]) """ Output: [18, 15, 19] [18, 19] [18, 15, 20, 19] [] [15, 19] [15, 19] [3, 0, 1, 2] [0, 3, 2, 1] """ ``` ``` java import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Comparator; import java.util.Collections; class Restaurant implements Comparable<Restaurant> { Restaurant(int id, int rate, int price, int distance) { } public int getID() { return 0; } @Override public int compareTo(Restaurant b) { return 0; } public static class Comparator1 implements Comparator<Restaurant> { public int compare(Restaurant a, Restaurant b) { return 0; } } } class Restaurants { public Restaurants(List<Restaurant> restaurants) { } public int[] filter(int min_price, int max_price, int min_rate) { return new int[]; } public static void main(String[] args) { // test List<Restaurant> restaurants = new ArrayList<Restaurant>(); restaurants.add(new Restaurant(20, 1, 20, 12)); restaurants.add(new Restaurant(15, 3, 19, 11)); restaurants.add(new Restaurant(19, 4, 19, 12)); restaurants.add(new Restaurant(18, 5, 20, 11)); Restaurants r = new Restaurants(restaurants); System.out.println(Arrays.toString(r.filter(0, 25, 3))); System.out.println(Arrays.toString(r.filter(0, 25, 4))); System.out.println(Arrays.toString(r.filter(0, 20, 1))); System.out.println(Arrays.toString(r.filter(0, 10, 1))); System.out.println(Arrays.toString(r.filter(0, 19, 1))); System.out.println(Arrays.toString(r.filter(19, 19, 3))); // case 6 restaurants = new ArrayList<Restaurant>(); restaurants.add(new Restaurant(3, 2, 3, 8)); restaurants.add(new Restaurant(0, 2, 4, 6)); restaurants.add(new Restaurant(2, 4, 5, 12)); restaurants.add(new Restaurant(1, 5, 6, 11)); Collections.sort(restaurants); for (Restaurant a: restaurants) { System.out.print(a.getID()); System.out.print(" "); } System.out.println(""); Collections.sort(restaurants, new Restaurant.Comparator1()); for (Restaurant a: restaurants) { System.out.print(a.getID()); System.out.print(" "); } System.out.println(""); } } ``` ## TestCase * `0 <= Distance, Price <= 10000` * `0 <= id <= 10000000` * The number of query(Called `filter`) will less than 1000 * We guarantee `id` is unique * We guarantee `min_price <= max_price` `N` is the number of restaurants `M` is the total length of output for each sample(The total length of `filter` output for each class after initial) * case1: 20 points: N = 10, M < 100 * case2: 20 points: N = 100000, M < 1000000 Special Case * case3: 20 points: N = 1000, M < 100*N * case4: 20 points: N = 9000, M < 100*N * case5: 10 points: N = 100000, M < 10*N * case6: 10 points: Implementation of compararsion. ## Time Limit Python: 4s Java: 1s # HW3-2 Warriors There are warriors standing in a line. Each warrior has two important properties: **STH** and **RNG**. **STH** stands for "strength", the power of each warrior. **RNG** stands for Range, the effective radius that the warrior can attack. Suppose that there are *N* warriors in this contest. An index *i* indicates one’s position (an integer coordinate). An attack will be blocked if there is a warrior with a higher or equal **STH** within the **RNG** distance. Formally speaking, let {$s_0$, $s_1$, ..., $s_{N−1}$} be the sequence of **STH** for the *N* warriors, and {$r_0$, $r_1$, ..., $r_{N−1}$} be the sequence of **RNG** for them, then the *i*-th warrior can attack the *j*-th warrior if and only if the following conditions are satisfied: * $|j − i| ≤ r_i$, * $s_j < s_i$ * $\{s_k\} < s_i$, for all *k* between *i* and *j* • $a_i$ = the index of the leftmost standing warrior that the *i*-th warrior can attack; • $b_i$ = the index of the rightmost standing warrior that the *i*-th warrior can attack. Please determine the sequence of pairs {($a_0$, $b_0$), ..., ($a_{N-1}$, $b_{N−1}$)}. To simplify the edge case, a warrior can attach itself. ## Hint * Stack * more hint update:10/29 22:07 * you might use two for loop from left to right and then from right to left * first compare the strength without limiting the range(regardless of the range) ## Template python: ``` python from typing import List class Warriors: def warriors(self, strength :List[int], attack_range :List[int]): """ Given the attributes of each warriors and output the minimal and maximum index of warrior can be attacked by each warrior. Parameters: strength (List[int]): The strength value of N warriors attack_range (List[int]): The range value of N warriors Returns: attack_interval (List[int]): The min and the max index that the warrior can attack. The format of output is 2N int array `[a0, b0, a1, b1, ...]` """ return [] ``` java: ```java import java.util.Arrays; public class Warriors { public int[] warriors(int[] strength, int[] range) { //Given the attributes of each warriors and output the minimal and maximum //index of warrior can be attacked by each warrior. return new int[]{}; } public static void main(String[] args) { Warriors sol = new Warriors(); System.out.println(Arrays.toString( sol.warriors(new int[] {11, 13, 11, 7, 15}, new int[] { 1, 8, 1, 7, 2}))); // Output: [0, 0, 0, 3, 2, 3, 3, 3, 2, 4] } } ``` ## Example ``` python if __name__ == "__main__": sol = Warriors() print(sol.warriors([11, 13, 11, 7, 15], [ 1, 8, 1, 7, 2])) """ # Output [0, 0, 0, 3, 2, 3, 3, 3, 2, 4] """ ``` ## TestCase `N` is the number of warriors `0 <= strength <= 1000000000` `0 <= attack_range <= M` `1 <= N` Time Limit: * Python: 4s * Java: 2s Case: * case1: 20 points: N <= 10, M < 10 * case2: 20 points: N <= 200000, M <= 200000 Special case * case3: 20 points: N <= 10000, M <= 5000 * case4: 20 points: N <= 400000, M <= 200000 * case5: 20 points: N <= 1000000, M <= 500000 Special Note:(2020/10/29) If RE in case2, sample1 to sample4, that's not your fault. Because attack_range is float type, you