Acá vamos a hablar de un "problema típico", que puede verse en este [[http://codeforces.com/contest/864/problem/E|link]] a codeforces. Básicamente, se tienen $n \leq 100$ ítems en peligro, cada ítem tiene un valor $v_i \leq 20$ que te da tener el ítem, un tiempo $t_i \leq 20$ que te lleva rescatar el ítem, y un momento $d_i \leq 2000$ a partir del cual el ítem ya es imposible de rescatar (se desintegra). Querés decidir qué ítems rescatar de manera de maximizar el valor total (la suma de los valores de los ítems rescatados). El post se llama "planificar tareas optimamente" porque muchas veces el mismo problema aparece como una serie de tareas a realizar, que tienen un deadline (momento en el cual ya no se puede realizar), que llevan un determinado tiempo realizarla, y que nos da una determinada ganancia. Es un problema equivalente, pero tenía el link de codeforces a mano. Se recomienda pensar el problema antes de seguir a ver la respuesta. Pregunta "pista importante": Dados dos ítems, qué nos indica en qué orden vamos a rescatarlos? La respuesta a esa pregunta es la observación clave del problema: Supongamos que sabemos que la solución óptima. Y nos preguntamos, tiene sentido rescatar primero a un ítem que se desintegra primero? Supongamos que rescatamos a dos ítems, $a$ y $b$, en ese orden, uno después del otro, tales que $d_a > d_b$, es decir el primer ítem se desintegra después que el segundo. Entonces, si al ítem $a$ lo vamos a rescatar en el momento $x_a$, al $b$ lo vamos a rescatar en el momento $x_b=x_a+t_a$. Como estamos en la solución óptima, entonces sabemos que $x_a+t_a0)mejorValor[i-1]..." y meter ifs en el medio. El código usa struct, de lo que pueden leer [[curso-cpp/struct|acá]]. #include using namespace std; #define forn(i,n) for(int i=0; i<(int)(n); i++) struct item{ int t, d, v, ind; }; bool compItem(item a, item b){ return a.d>n; vector items; int termino=0; forn(i, n){ item it; cin>>it.t>>it.d>>it.v; it.ind=i+1; termino=max(termino, it.d); items.push_back(it); } sort(items.begin(), items.end(), compItem); vector< vector > mejorValor(n+1, vector(termino+2, 0)); forn(i, n){ forn(j, termino+2){ if(j-items[i].t>=0 && jmejorValor[n][lastRescueMoment]){ lastRescueMoment=j; } } cout< rescato; for(int i=n-1; i>=0; i--){ if(lastRescueMoment>=items[i].t && mejorValor[i+1][lastRescueMoment]==mejorValor[i][lastRescueMoment-items[i].t]+items[i].v){ lastRescueMoment-=items[i].t; rescato.push_back(items[i].ind); } } reverse(rescato.begin(), rescato.end()); cout< ** Observaciones ** El hecho de primero ordenar, y luego usar como subproblema "los primeros $i$" es algo bastante típico en programación dinámica. Algo que también sirve mucho mucho es **suponer que tenemos la solución óptima**, para ver por ejemplo el orden en el que podemos obtenerla, o si hay algo que podemos descartar.