Skip to Content

Radio Contact

Análisis oficial (C++) 

Solución en video

Nota: La solución en video podría no ser la misma que las otras soluciones. Código en C++.

Video de YouTube (MOei3fIEPR0)

Explicación

La observación clave de dp\texttt{dp} a hacer aquí ya está enunciada en el enunciado: “Farmer John can either stay put at his current location, or take one step forward”, e igual para Bessie. Así, al construir nuestro dp\texttt{dp}, podemos definir dp[i][j]\texttt{dp}[i][j] como la mejor distancia en el movimiento ii de Farmer John y el movimiento jj de Bessie.

Notemos que es difícil calcular una distancia acumulada si dejamos el string sin procesar (es decir, si leemos directamente del string). Para resolver esto, podemos simplemente calcular las coordenadas (i,j)(i,j) en cada paso del camino de Bessie y de Farmer John. En nuestra implementación, mapeamos cada carácter a sus arreglos dx, dy correspondientes para aplicar los cambios apropiados, almacenando la posición de Farmer John en el movimiento ii como jl[i]\texttt{jl}[i] y la posición de Bessie en el movimiento jj como bl[j]\texttt{bl}[j].

Después de esto, empezamos a construir nuestro dp\texttt{dp}:

Sucede una de las siguientes:

  1. Farmer John da un paso (i+1)(i+1):

    dp[i+1][j]=min(dp[i+1][j],dp[i][j]+dist(jl[i+1],bl[j]))\texttt{dp}[i+1][j] = \min(\texttt{dp}[i+1][j], \texttt{dp}[i][j] + \text{dist}(\texttt{jl}[i+1], \texttt{bl}[j]))
  2. Bessie da un paso (j+1)(j+1):

    dp[i][j+1]=min(dp[i][j+1],dp[i][j]+dist(jl[i],bl[j+1]))\texttt{dp}[i][j+1] = \min(\texttt{dp}[i][j+1], \texttt{dp}[i][j] + \text{dist}(\texttt{jl}[i], \texttt{bl}[j+1]))
  3. Farmer John y Bessie dan pasos (i+1)(i+1) y (j+1)(j+1):

    dp[i+1][j+1]=min(dp[i+1][j+1],dp[i][j]+dist(jl[i+1],bl[j+1]))\texttt{dp}[i+1][j+1] = \min(\texttt{dp}[i+1][j+1], \texttt{dp}[i][j] + \text{dist}(\texttt{jl}[i+1], \texttt{bl}[j+1]))

Implementación

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

// CodeSnip{CPP Short Template} int N, M; const int INF = 1e9 + 7; const int MX = 1e3 + 1; int sq(int a) { return a * a; } int dist(pi a, pi b) { // distancia al cuadrado entre dos puntos return sq(a.f - b.f) + sq(a.s - b.s); } map<char, int> md{{'N', 0}, {'E', 1}, {'S', 2}, {'W', 3}}; const int dx[4]{0, 1, 0, -1}; const int dy[4]{1, 0, -1, 0}; // i = paso actual de John // j = paso actual de Bessie int dp[MX][MX]; int main() { setIO("radio"); cin >> N >> M; vector<pi> jl(N + 1); // ubicación de john vector<pi> bl(M + 1); // ubicación de bessie int a, b; cin >> a >> b; jl[0] = {a, b}; // ubicación inicial de john cin >> a >> b; bl[0] = {a, b}; // ubicación inicial de bessie string jS, bS; // strings de movimiento de john y bessie cin >> jS >> bS; // calcular los movimientos de ambos // dx[md[jS[i]]] puede parecer complicado, pero solo mapea el carácter a su // cambio for (int i = 0; i < sz(jS); i++) { jl[i + 1] = {jl[i].f + dx[md[jS[i]]], jl[i].s + dy[md[jS[i]]]}; } for (int i = 0; i < sz(bS); i++) { bl[i + 1] = {bl[i].f + dx[md[bS[i]]], bl[i].s + dy[md[bS[i]]]}; } // o se mueve john, o se mueve bessie, o se mueven ambos fill_n(dp[0], MX * MX, INF); dp[0][0] = 0; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + dist(jl[i + 1], bl[j])); dp[i][j + 1] = min(dp[i][j + 1], dp[i][j] + dist(jl[i], bl[j + 1])); dp[i + 1][j + 1] = min(dp[i + 1][j + 1], dp[i][j] + dist(jl[i + 1], bl[j + 1])); } } cout << dp[N][M] << "\n"; }
import java.io.*; import java.util.*; public class radio { public static int[][] fjLocs; public static int[][] bLocs; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("radio.in")); PrintWriter pw = new PrintWriter(new FileWriter("radio.out")); StringTokenizer st = new StringTokenizer(br.readLine()); int N = Integer.parseInt(st.nextToken()); int M = Integer.parseInt(st.nextToken()); fjLocs = new int[N + 1][2]; // Ubicaciones de FJ. bLocs = new int[M + 1][2]; // Ubicaciones de Bessie. // Ubicación original de FJ. st = new StringTokenizer(br.readLine()); fjLocs[0][0] = Integer.parseInt(st.nextToken()); fjLocs[0][1] = Integer.parseInt(st.nextToken()); // Ubicación original de Bessie. st = new StringTokenizer(br.readLine()); bLocs[0][0] = Integer.parseInt(st.nextToken()); bLocs[0][1] = Integer.parseInt(st.nextToken()); // Encontrar las ubicaciones que visitan ambos. String fjPath = br.readLine(); String bPath = br.readLine(); fill(fjLocs, fjPath); fill(bLocs, bPath); /* * dp[i][j] es el costo mínimo para que * FJ dé i pasos, y para que Bessie dé j pasos. */ int[][] dp = new int[N + 1][M + 1]; // Si FJ se mueve, y Bessie se queda quieta. for (int i = 1; i <= N; i++) { dp[i][0] = dp[i - 1][0] + cost(fjLocs[i], bLocs[0]); } // Si FJ se queda quieto, y Bessie se mueve. for (int j = 1; j <= M; j++) { dp[0][j] = dp[0][j - 1] + cost(fjLocs[0], bLocs[j]); } for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { // El costo actual en esta celda. int curCost = cost(fjLocs[i], bLocs[j]); // Calcular distintos costos según quién se mueve. int bothMove = dp[i - 1][j - 1] + curCost; int fjMove = dp[i - 1][j] + curCost; int bMove = dp[i][j - 1] + curCost; dp[i][j] = Math.min(Math.min(bothMove, fjMove), bMove); } } pw.println(dp[N][M]); pw.close(); } // Llenar los arreglos de ubicación de FJ y Bessie. public static void fill(int[][] loc, String dir) { for (int i = 1; i <= dir.length(); i++) { loc[i][0] = loc[i - 1][0]; loc[i][1] = loc[i - 1][1]; // Cambio de ubicación según la dirección. char c = dir.charAt(i - 1); if (c == 'N') { loc[i][1]++; } if (c == 'E') { loc[i][0]++; } if (c == 'S') { loc[i][1]--; } if (c == 'W') { loc[i][0]--; } } } // Cuadrado de la distancia entre los puntos a y b. public static int cost(int[] a, int[] b) { return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]); } }