He estado tratando de hacer este problema HackerEarth pero los últimos casos de prueba siempre parece que el tiempo de espera
Planteamiento del problema: https://www.hackerearth.com/practice/algorithms/searching/linear-search/practice-problems/algorithm/joker-and-thieves-53e59f4a/
Soy un estudiante de primer año, por lo que no se sabe muy bien cómo optimizar así que
Traté de mirar la solución de Java, pero sólo hay que poner los casos más grandes en el código, eliminando de forma eficaz la necesidad de optimizarlo
import java.io.*;
import java.util.*;
public class police {
static int t,n,k;
static char[][] test;
static int max = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
t = Integer.parseInt(st.nextToken());
for (int i = 0; i < t; i++) {
st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
k = Integer.parseInt(st.nextToken());
test = new char[n][n];
int ret = 0;
for (int b = 0; b < n; b++) {
st = new StringTokenizer(br.readLine());
for (int a = 0; a < n; a++) {
test[b][a] = st.nextToken().charAt(0);
}
}
for (int b = 0; b < n; b++) {
ret += solve(test[b]); //calculate each row
}
System.out.println(ret);
}
}
static int solve(char[] a) { //given a row, calculate the maximum number of catches
int ret = 0;
for (int i = 0; i < n; i++) {
if (a[i] == 'P') {
for (int b = i - k; b <= i + k; b++) { //scan area to see if police can catch a thief
if (b >= 0 && b < n && a[b] == 'T') {
a[b] = 'C'; //caught
break;
}
}
a[i] = 'U'; //used
}
}
for (int i = 0; i < n; i++) //count
if (a[i] == 'C')
ret++;
return ret;
}
}
Estoy bastante seguro de que tiene algo que ver con el método de resolver, si alguien me podría ayudar a que sería increíble
Tiene usted razón, el enfoque que está utilizando en su solve
método es la causa del tiempo de espera.
En primer lugar es necesario tener una idea acerca de complejidad del algoritmo y la notación O grande
Las restricciones del problema son:
1 <= N <= 1000
1 <= K <= N * N
éstos indican que la complejidad de su solución debe ser como máximo O(N * N)
. En otras palabras a lo más dos anidados para bucles cada uno con una complejidad O (N).
Y en su solución que está haciendo lo siguiente:
for (int b = 0; b < n; b++) {
ret += solve(test[b]); //calculate each row
}
OK, este bucle es esencial, ya que tiene que iterar sobre todas las filas de la cuadrícula. Complejidad:O(N)
Luego, en el método de resolver:
for (int i = 0; i < n; i++) {
if (a[i] == 'P') {
for (int b = i - k; b <= i + k; b++) { //scan area to see if police can catch a thief
if (b >= 0 && b < n && a[b] == 'T') {
a[b] = 'C'; //caught
break;
}
}
a[i] = 'U'; //used
}
}
Estos bucles for anidados son la causa real del problema, la complejidad del bucle exterior es O(N)
ya la complejidad bucle interno podría ser también O(N)
un alto valor de K
. Por lo tanto la complejidad total de los tres bucles podría llegar a O(N * N * N)
lo que sin duda tiempo de espera.
Aquí está mi solución a este problema, lo único que he modificado el solve
método:
static int solve(char[] a) { //given a row, calculate the maximum number of catches
int ret = 0;
ArrayDeque<Integer> policeMenQueue = new ArrayDeque<>(); // queue for holding positions of policemen
ArrayDeque<Integer> thievesQueue = new ArrayDeque<>(); // queue for positions of thieves
for (int i = 0; i < n; i++) {
if(!policeMenQueue.isEmpty()) { // check if the leftmost policeman can catch a thief at current position (i)
Integer mostLeftPoliceMan = policeMenQueue.getFirst();
if(i - mostLeftPoliceMan > k) { // if he cannot then we must remove him as he will no longer be able to catch any thieves
policeMenQueue.removeFirst();
}
}
if(!thievesQueue.isEmpty()) { // check if the leftmost thief can be caught be a policeman at current position (i)
Integer mostLeftThief = thievesQueue.getFirst();
if(i - mostLeftThief > k) { // if not then we must remove him as he will no longer be caught by any policemen
thievesQueue.removeFirst();
}
}
if(a[i] == 'P') {
if(!thievesQueue.isEmpty()) { // the leftmost thief can be caught by current policeman
ret++;
thievesQueue.removeFirst(); // ok this thief is caught, remove him
} else {
policeMenQueue.addLast(i); // just add the policeman to keep his position in the queue
}
}
if(a[i] == 'T') {
if(!policeMenQueue.isEmpty()) { // the current thief can be caught by the leftmost policeman
ret++;
policeMenQueue.removeFirst(); // ok this policeman has already caught a thief (used), remove him
} else {
thievesQueue.addLast(i); // just add the thief to keep his position in the queue
}
}
}
return ret;
}
Mi idea: bucle en cada fila, de izquierda a derecha y como afirma el problema: cada policía puede coger sólo un ladrón y queremos maximizar el número de ladrones atrapados, por lo que está a nuestro favor que cada ladrón es capturado por el policía más a la izquierda (ya que estamos yendo de izquierda a derecha).
Por ejemplo, consideremos esta fila:
P P T T
e imaginar que K = 2
Es nuestro favor ese ladrón en la posición 3
ser capturado por el policía en la posición 1
que este policía no puede atrapar al ladrón de la posición 4
y por supuesto la policía en la posición 2
pueden tomar dos ladrones en este caso, pero recuerda que tenemos que maximizar el número de ladrones capturados y cada policía puede coger sólo un ladrón, por lo que queremos que cada ladrón de ser atrapado por la policía más a la izquierda que lo pueda coger.
Mi solución depende de la queue
estructura de datos ( ArrayDeque
en Java), si usted no sabe cómo funciona o por qué lo estoy usando echar un vistazo aquí: https://www.tutorialspoint.com/data_structures_algorithms/dsa_queue.htm