Skip to Content

Rest Stops

Análisis oficial (C++) 

Solución en video

Por Vivian Han

Video de YouTube (gyg047C-754)

Código de la solución en video
// #define reststops 1; // #ifdef reststops #include <fstream> #include <iostream> using namespace std; int32_t trailLen, stopNum, fRate, bRate; int32_t x[100000]; int32_t c[100000]; bool good[100000]; int main() { ifstream in; in.open("reststops.in"); in >> trailLen >> stopNum >> fRate >> bRate; // leemos los datos de las paradas for (int i = 0; i < stopNum; i++) { in >> x[i] >> c[i]; } // hallamos todas las paradas "mejores" int32_t max = 0; for (int i = stopNum - 1; i >= 0; i--) { good[i] = false; if (c[i] > max) { // no hay paradas después de i que sean "mejores" good[i] = true; max = c[i]; } } // simulamos todo el sendero long long prevStopPos = 0; long long ans = 0; for (int i = 0; i < stopNum; i++) { if (good[i]) { long long travelDist = x[i] - prevStopPos; long long fTime = travelDist * fRate; long long bTime = travelDist * bRate; long long restTime = fTime - bTime; ans += restTime * c[i]; prevStopPos = x[i]; } } // */ ofstream out; out.open("reststops.out"); out << ans << endl; out.close(); // cout << ans << endl; return 0; } // #endif
import java.io.*; public class RestStops { static int[] x, c; static boolean[] good; public static void main(String[] args) { try { BufferedReader br = new BufferedReader(new FileReader("reststops.in")); String[] line = br.readLine().split(" "); int trailLen = Integer.parseInt(line[0]); // este valor nunca se usa... int stopNum = Integer.parseInt(line[1]); int fRate = Integer.parseInt(line[2]); int bRate = Integer.parseInt(line[3]); x = new int[stopNum]; c = new int[stopNum]; good = new boolean[stopNum]; // leemos los datos de las paradas for (int i = 0; i < stopNum; i++) { line = br.readLine().split(" "); x[i] = Integer.parseInt(line[0]); c[i] = Integer.parseInt(line[1]); } br.close(); // hallamos todas las paradas "mejores" int max = 0; for (int i = stopNum - 1; i >= 0; i--) { if (c[i] > max) { // no hay paradas después de i que sean "mejores" good[i] = true; max = c[i]; } } // simulamos todo el sendero int prevStopPos = 0; long ans = 0; for (int i = 0; i < stopNum; i++) { if (good[i]) { long travelDist = x[i] - prevStopPos; long fTime = travelDist * fRate; long bTime = travelDist * bRate; long restTime = fTime - bTime; ans += restTime * c[i]; prevStopPos = x[i]; } } BufferedWriter bw = new BufferedWriter(new FileWriter("reststops.out")); bw.write(ans + "\n"); bw.close(); } catch (Exception e) { System.out.println(e.getMessage()); } } }

Explicación

Supongamos que temprano en la caminata hay una parada con sabor AA, pero más adelante hay una parada con sabor BB donde B>AB>A. Entonces, nunca es óptimo que Bessie pase tiempo en la primera parada con sabor AA. Si lo hiciera, podría pasar la misma cantidad de tiempo en la parada posterior y ganar más unidades de sabor; igual nunca quedaría detrás de Farmer John. Así, las únicas paradas en las que Bessie podría detenerse son las que tienen más sabor que cualquier parada posterior.

Podemos hallar estas paradas “maximalmente a la derecha” en un solo barrido de derecha a izquierda (o de fin a inicio), llevando la cuenta del mayor sabor visto hasta ahora. Si la parada actual supera el mayor valor visto hasta ahora, es “maximalmente a la derecha”.

Ahora podemos aplicar un algoritmo voraz: nunca parar en paradas que no sean maximalmente a la derecha. Bessie debería detenerse en una parada maximalmente a la derecha el mayor tiempo posible (es decir, hasta que Farmer John la alcance). Luego sigue hasta la siguiente parada maximalmente a la derecha.

Para ver la corrección de este algoritmo voraz, supongamos que Bessie no pasó tanto tiempo como podía en alguna parada maximalmente a la derecha RR. Entonces dejaría esta parada tt segundos antes, para algún tt positivo. Supongamos que el siguiente lugar en el que Bessie se detiene es la parada rr. Podríamos mejorar la ingesta de sabor de Bessie haciendo que pase 11 segundo menos en rr y 11 segundo más en la parada RR. Se puede verificar que Bessie igual nunca quedaría detrás de Farmer John, y como el sabor en RR es mayor que el sabor en rr, mejoramos el resultado de Bessie. Por lo tanto ninguna solución óptima deja una parada maximalmente a la derecha antes de tiempo, y nuestro algoritmo voraz es correcto.

Implementación

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

#include <fstream> #include <iostream> #include <vector> using namespace std; int main() { ifstream in("reststops.in"); int trail_len; // no se usa int stop_num; int f_rate; int b_rate; in >> trail_len >> stop_num >> f_rate >> b_rate; vector<int> x(stop_num); // posición de cada parada vector<int> c(stop_num); // valor de sabor de cada parada for (int i = 0; i < stop_num; i++) { in >> x[i] >> c[i]; } // hallamos todas las paradas "mejores" vector<bool> good(stop_num); int max_tastiness = 0; for (int i = stop_num - 1; i >= 0; i--) { if (c[i] > max_tastiness) { // no hay paradas después de i que sean "mejores" good[i] = true; max_tastiness = c[i]; } } int total = 0; for (bool i : good) total += i; cout << total << endl; // simulamos todo el sendero long long prev_stop_pos = 0; long long ans = 0; for (int i = 0; i < stop_num; i++) { if (good[i]) { long long travel_dist = x[i] - prev_stop_pos; long long f_time = travel_dist * f_rate; long long b_time = travel_dist * b_rate; long long rest_time = f_time - b_time; ans += rest_time * c[i]; prev_stop_pos = x[i]; } } ofstream("reststops.out") << ans << endl; }
import java.io.*; public class RestStops { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("reststops.in")); String[] line = br.readLine().split(" "); int trailLen = Integer.parseInt(line[0]); // nunca se usa int stopNum = Integer.parseInt(line[1]); int fRate = Integer.parseInt(line[2]); int bRate = Integer.parseInt(line[3]); int[] x = new int[stopNum]; // posición de cada parada int[] c = new int[stopNum]; // valor de sabor de cada parada for (int i = 0; i < stopNum; i++) { line = br.readLine().split(" "); x[i] = Integer.parseInt(line[0]); c[i] = Integer.parseInt(line[1]); } br.close(); // hallamos todas las paradas "mejores" boolean[] good = new boolean[stopNum]; int maxTastiness = 0; for (int i = stopNum - 1; i >= 0; i--) { if (c[i] > maxTastiness) { // no hay paradas después de i que sean "mejores" good[i] = true; maxTastiness = c[i]; } } // simulamos todo el sendero int prevStopPos = 0; long ans = 0; for (int i = 0; i < stopNum; i++) { if (good[i]) { long travelDist = x[i] - prevStopPos; long fTime = travelDist * fRate; long bTime = travelDist * bRate; long restTime = fTime - bTime; ans += restTime * c[i]; prevStopPos = x[i]; } } PrintWriter pw = new PrintWriter("reststops.out"); pw.println(ans); pw.close(); } }
with open("reststops.in") as read: # trail_len no se usa trail_len, stop_num, f_rate, b_rate = [int(i) for i in read.readline().split()] x = [] # posición de cada parada c = [] # valor de sabor de cada parada for _ in range(stop_num): a, b = [int(i) for i in read.readline().split()] x.append(a) c.append(b) # hallamos todas las paradas "mejores" good = [False for _ in range(stop_num)] max_tastiness = 0 for i in range(stop_num - 1, -1, -1): if c[i] > max_tastiness: # no hay paradas después de i que sean "mejores" good[i] = True max_tastiness = c[i] # simulamos todo el sendero prev_stop_pos = 0 ans = 0 for i in range(stop_num): if good[i]: travel_dist = x[i] - prev_stop_pos f_time = travel_dist * f_rate b_time = travel_dist * b_rate rest_time = f_time - b_time ans += rest_time * c[i] prev_stop_pos = x[i] print(ans, file=open("reststops.out", "w"))