Skip to Content

Milk Visits

Análisis oficial (C++) 

Complejidad temporal: O(N+M)\mathcal{O}(N + M)

Hacemos una búsqueda sobre el árbol, identificando las componentes conexas de vacas que tienen todas la misma raza.

En el caso de prueba de ejemplo hay 33 componentes conexas:

  • Componente 00: Granjas 11, 22 y 44
  • Componente 11: Granja 33
  • Componente 22: Granja 55

Luego, asignamos a las granjas de cada componente un número correspondiente a la componente en la que están. Por ejemplo, en el caso de prueba de ejemplo, la granja 11 recibiría el número 00, la 33 recibiría el número 11, y así sucesivamente.

Al comprobar si un granjero visitante que va de la granja AA a la BB estará contento, hay dos casos posibles:

  1. Las granjas AA y BB son parte de la misma componente. Esto significa que el camino entre AA y BB solo contiene vacas de la misma raza. Si el granjero prefiere leche de esta raza, debemos imprimir 11 y 00 en caso contrario.
  2. Las granjas AA y BB son parte de componentes distintas. Esto significa que el granjero siempre estará satisfecho porque el camino entre AA y BB contiene ambas razas de vacas, y por lo tanto siempre debemos imprimir 11.

Aquí hay un recorrido de las consultas del caso de prueba de ejemplo:

  1. Las granjas 11 y 44 están en la misma componente, y como la vaca preferida del Granjero 11 es Holstein, estará satisfecho. (11)
  2. Las granjas 11 y 44 están en la misma componente, pero como la vaca preferida del Granjero 22 es Guernsey, estará insatisfecho. (00)
  3. Las granjas 11 y 33 están en componentes distintas, así que el Granjero 33 estará satisfecho. (11)
  4. Misma lógica que la consulta 33. (11)
  5. La granja 55 es Guernsey, y la vaca preferida del Granjero 55 es Holstein, estará insatisfecho. (00)
#include <algorithm> #include <cassert> #include <fstream> #include <iostream> #include <vector> using std::cout; using std::endl; using std::vector; int main() { std::ifstream read("milkvisits.in"); int farm_num; int query_num; read >> farm_num >> query_num; vector<char> farms(farm_num); for (char &f : farms) { read >> f; assert(f == 'G' || f == 'H'); } vector<vector<int>> neighbors(farm_num); for (int f = 0; f < farm_num - 1; f++) { int f1, f2; read >> f1 >> f2; f1--; f2--; neighbors[f1].push_back(f2); neighbors[f2].push_back(f1); } // Procesamos el árbol y detectamos las distintas componentes int component_num = 0; vector<int> component(farm_num, -1); for (int f = 0; f < farm_num; f++) { // No procesamos una granja si ya fue visitada if (component[f] != -1) { continue; } vector<int> frontier{f}; char type = farms[f]; while (!frontier.empty()) { int curr = frontier.back(); frontier.pop_back(); // Asignamos el número de componente actual a la granja component[curr] = component_num; for (int n : neighbors[curr]) { // Visitamos un vecino si es nuevo y es del mismo tipo if (farms[n] == type && component[n] == -1) { frontier.push_back(n); } } } component_num++; } std::ofstream written("milkvisits.out"); for (int q = 0; q < query_num; q++) { int a, b; char milk; read >> a >> b >> milk; a--; b--; if (component[a] == component[b]) { /* * Si a y b están en la misma componente, * comprobamos si el tipo de leche es el que el granjero prefiere */ written << (farms[a] == milk); } else { // Imprimimos 1 en caso contrario porque se visitarán ambos tipos de leche written << 1; } } }
import java.io.*; import java.util.*; public class MilkVisits { public static void main(String[] args) throws IOException { BufferedReader read = new BufferedReader(new FileReader("milkvisits.in")); StringTokenizer initial = new StringTokenizer(read.readLine()); int farmNum = Integer.parseInt(initial.nextToken()); int queryNum = Integer.parseInt(initial.nextToken()); String farms = read.readLine(); List<Integer>[] neighbors = new ArrayList[farmNum]; for (int f = 0; f < farmNum; f++) { neighbors[f] = new ArrayList<>(); } for (int f = 0; f < farmNum - 1; f++) { StringTokenizer road = new StringTokenizer(read.readLine()); int f1 = Integer.parseInt(road.nextToken()) - 1; int f2 = Integer.parseInt(road.nextToken()) - 1; neighbors[f1].add(f2); neighbors[f2].add(f1); } // Procesamos el árbol y detectamos las distintas componentes int componentNum = 0; int[] component = new int[farmNum]; Arrays.fill(component, -1); for (int f = 0; f < farmNum; f++) { // No procesamos una granja si ya fue visitada if (component[f] != -1) { continue; } ArrayDeque<Integer> frontier = new ArrayDeque<>(); frontier.add(f); char type = farms.charAt(f); while (!frontier.isEmpty()) { int curr = frontier.poll(); // Asignamos el número de componente actual a la granja component[curr] = componentNum; for (int n : neighbors[curr]) { // Visitamos un vecino si es nuevo y es del mismo tipo if (farms.charAt(n) == type && component[n] == -1) { frontier.add(n); } } } componentNum++; } PrintWriter written = new PrintWriter("milkvisits.out"); for (int q = 0; q < queryNum; q++) { StringTokenizer query = new StringTokenizer(read.readLine()); int a = Integer.parseInt(query.nextToken()) - 1; int b = Integer.parseInt(query.nextToken()) - 1; char milk = query.nextToken().charAt(0); if (component[a] == component[b]) { /* * Si a y b están en la misma componente, * comprobamos si el tipo de leche es el que el granjero * prefiere */ written.print(farms.charAt(a) == milk ? 1 : 0); } else { // Imprimimos 1 en caso contrario porque se visitarán ambos tipos de leche written.print(1); } } written.close(); } }
with open("milkvisits.in") as read: farm_num, query_num = [int(i) for i in read.readline().split()] farms = read.readline() neighbors = [[] for _ in range(farm_num)] for f in range(farm_num - 1): f1, f2 = [int(i) - 1 for i in read.readline().split()] neighbors[f1].append(f2) neighbors[f2].append(f1) queries = [] for _ in range(query_num): query = read.readline().split() query[0], query[1] = int(query[0]) - 1, int(query[1]) - 1 queries.append(query) # Procesamos el árbol y detectamos las distintas componentes component_num = 0 component = [-1 for _ in range(farm_num)] for f in range(farm_num): # No procesamos una granja si ya fue visitada if component[f] != -1: continue frontier = [f] curr_type = farms[f] while frontier: curr = frontier.pop() # Asignamos el número de componente actual a la granja component[curr] = component_num for n in neighbors[curr]: # Visitamos un vecino si es nuevo y es del mismo tipo if farms[n] == curr_type and component[n] == -1: frontier.append(n) component_num += 1 with open("milkvisits.out", "w") as written: for a, b, milk in queries: if component[a] == component[b]: """ Si a y b están en la misma componente, comprobamos si el tipo de leche es el que el granjero prefiere """ print(1 if farms[a] == milk else 0, end="", file=written) else: # Imprimimos 1 en caso contrario porque se visitarán ambos tipos de leche print(1, end="", file=written) print(file=written)