|
1 | 1 | package by.andd3dfx.common;
|
2 | 2 |
|
3 | | -import lombok.Data; |
4 | | - |
5 | 3 | import java.util.Arrays;
|
6 | | -import java.util.HashMap; |
7 | 4 | import java.util.HashSet;
|
8 | | -import java.util.Map; |
9 | 5 | import java.util.Set;
|
10 | 6 | import java.util.stream.Collectors;
|
11 | 7 |
|
|
29 | 25 | */
|
30 | 26 | public class InfectionDistribution {
|
31 | 27 |
|
32 | | - /** |
33 | | - * Initial solution |
34 | | - */ |
35 | | - public static int weeksToInfectAllCities_usingIterationByRoads(int citiesAmount, int[][] roads, int[] infected) { |
36 | | - int weeksCount = 0; |
37 | | - var infectedCitiesSet = Arrays.stream(infected).boxed() |
38 | | - .collect(Collectors.toSet()); |
39 | | - var roadsSet = buildRoadsSet(roads); |
40 | | - |
41 | | - while (!isAllInfected(citiesAmount, infectedCitiesSet)) { |
42 | | - var infectedOnThisIteration = processOneWeek(roadsSet, infectedCitiesSet); |
43 | | - |
44 | | - if (infectedOnThisIteration == 0) { |
45 | | - throw new IllegalArgumentException("Could not infect all cities!"); |
46 | | - } |
47 | | - weeksCount++; |
48 | | - } |
49 | | - |
50 | | - return weeksCount; |
51 | | - } |
52 | | - |
53 | | - private static boolean isAllInfected(int citiesAmount, Set<Integer> infectedCitiesSet) { |
54 | | - return infectedCitiesSet.size() == citiesAmount; |
55 | | - } |
56 | | - |
57 | | - private static Set<Road> buildRoadsSet(int[][] roads) { |
58 | | - return Arrays.stream(roads) |
59 | | - .map(Road::new) |
60 | | - .collect(Collectors.toSet()); |
61 | | - } |
62 | | - |
63 | | - private static int processOneWeek(Set<Road> roads, Set<Integer> infectedCitiesSet) { |
64 | | - var initialCitiesSet = new HashSet<>(infectedCitiesSet); |
65 | | - |
66 | | - var it = roads.iterator(); |
67 | | - while (it.hasNext()) { |
68 | | - var road = it.next(); |
69 | | - |
70 | | - if (initialCitiesSet.contains(road.start)) { |
71 | | - infectedCitiesSet.add(road.end); |
72 | | - it.remove(); |
73 | | - continue; |
74 | | - } |
75 | | - |
76 | | - if (initialCitiesSet.contains(road.end)) { |
77 | | - infectedCitiesSet.add(road.start); |
78 | | - it.remove(); |
79 | | - } |
80 | | - } |
81 | | - |
82 | | - return infectedCitiesSet.size() - initialCitiesSet.size(); |
83 | | - } |
84 | | - |
85 | | - @Data |
86 | | - private static class Road { |
87 | | - private int start; |
88 | | - private int end; |
89 | | - |
90 | | - public Road(int[] road) { |
91 | | - this.start = road[0]; |
92 | | - this.end = road[1]; |
93 | | - } |
94 | | - } |
95 | | - |
96 | | - /** |
97 | | - * Enhanced solution |
98 | | - */ |
99 | | - public static int weeksToInfectAllCities_usingIterationByInfectedCities(int citiesAmount, int[][] roads, int[] infected) { |
100 | | - var routesMap = new HashMap<Integer, Set<Integer>>(); |
| 28 | + public static int weeksToInfectAllCities(int citiesAmount, int[][] roads, int[] infected) { |
| 29 | + var adjMatrix = new boolean[citiesAmount][citiesAmount]; // adjacency matrix |
101 | 30 | Arrays.stream(roads).forEach(road -> {
|
102 | | - populate(routesMap, road, 0, 1); |
103 | | - populate(routesMap, road, 1, 0); |
| 31 | + adjMatrix[road[0]][road[1]] = true; |
| 32 | + adjMatrix[road[1]][road[0]] = true; |
104 | 33 | });
|
105 | 34 |
|
106 | 35 | var weeksAmount = 0;
|
107 | 36 | var infectedCities = Arrays.stream(infected).boxed().collect(Collectors.toSet());
|
108 | | - var sourceCities = new HashSet<>(infectedCities); |
109 | 37 |
|
110 | | - while (!isAllInfected(citiesAmount, infectedCities)) { |
111 | | - if (sourceCities.isEmpty()) { |
112 | | - throw new IllegalArgumentException("Could not infect all cities!"); |
| 38 | + while (infectedCities.size() < citiesAmount) { |
| 39 | + var newCities = determineNewInfectedCities(infectedCities, adjMatrix); |
| 40 | + if (newCities.isEmpty()) { |
| 41 | + return -1; |
113 | 42 | }
|
114 | 43 |
|
115 | | - var newInfectedCities = determineNewInfectedCities(routesMap, infectedCities, sourceCities); |
116 | | - infectedCities.addAll(newInfectedCities); |
117 | | - sourceCities = newInfectedCities; |
| 44 | + infectedCities.addAll(newCities); |
| 45 | + |
118 | 46 | weeksAmount++;
|
119 | 47 | }
|
120 | 48 |
|
121 | 49 | return weeksAmount;
|
122 | 50 | }
|
123 | 51 |
|
124 | | - private static HashSet<Integer> determineNewInfectedCities( |
125 | | - Map<Integer, Set<Integer>> routesMap, Set<Integer> infectedCities, Set<Integer> sourceCities) { |
126 | | - var newInfectedCities = new HashSet<Integer>(); |
127 | | - for (var city : sourceCities) { |
128 | | - if (!routesMap.containsKey(city)) { |
129 | | - continue; |
| 52 | + private static Set<Integer> determineNewInfectedCities(Set<Integer> infectedCities, boolean[][] adjMatrix) { |
| 53 | + var n = adjMatrix.length; |
| 54 | + var newCities = new HashSet<Integer>(); |
| 55 | + for (var city : infectedCities) { |
| 56 | + for (int i = 0; i < n; i++) { |
| 57 | + if (adjMatrix[city][i] && !infectedCities.contains(i)) { |
| 58 | + newCities.add(i); |
| 59 | + } |
130 | 60 | }
|
131 | | - |
132 | | - var citiesToInfect = new HashSet<>(routesMap.get(city)); |
133 | | - citiesToInfect.removeAll(infectedCities); |
134 | | - |
135 | | - newInfectedCities.addAll(citiesToInfect); |
136 | 61 | }
|
137 | | - return newInfectedCities; |
138 | | - } |
139 | 62 |
|
140 | | - private static void populate(Map<Integer, Set<Integer>> routesMap, int[] road, int i, int j) { |
141 | | - if (!routesMap.containsKey(road[i])) { |
142 | | - routesMap.put(road[i], new HashSet<>()); |
143 | | - } |
144 | | - routesMap.get(road[i]).add(road[j]); |
| 63 | + return newCities; |
145 | 64 | }
|
146 | 65 | }
|
0 commit comments