Problema con algoritmo de recusividad y Programacion Dinamica

Hola buenas, queria pediros ayuda porque estoy un poco atascado. Resulta que estoy de erasmus en italia y tengo un examen el jueves de Algoritmo y estructura de Datos y estoy haciendo examenes anteriores para practicar. Me he topado con uno que no me sale(bueno hay mas de uno) y no se como hacerlo. He estado en tutoria, pero entre que no entiendo bien como se tiene que hacer el ejercicio y lo que me dice la tía esta en italiano,no me entero. El problema dice así.

A lo lago de un rio hay n puestos indicados con 0,1,.....n. En cada uno se puede alquilar una barca que puede ser devuelta en otro puesto.Es imposible ir en contra corriente. EL coste de la alquilar una barca de un punto de partida(i) a un punto de llegada es(j), y se denota por C(i,j). Es posible que para ir de i a j sea más economico efectuar algunos cambios de barca a lo largo del rio, que alquilar una unica canoa. Si se alguila una nueva en los puestos k1<k2... <kl el coste total del alquiler sera C(i,k1)+c(k1,k2)+....+C(kl,j). El coste minimo para ir del puesto i al puesto j es indicado por S(i,j)

1) calcular una funcion recursiva que calcule cada par de i,j. En particular se quiere S(0,n-1)
2) Una funcion no recursiva que calcule S(i,j). En particular S(0,n-1). (Tecnica de programacion dinamica)


Sugerencia para la solucion:

El subproblema generico es establecer el coste minimo S(i,j) que necesitas pagar para ir del puesto i al puesto j con i<j. Este valor puede ser calculado como el minimo de C(i,j) (es decir el coste directo para ir de i a j sin paradas intermedias) y el minimo entre la suma minima para ir del puesto i al puesto j con puestos intermerdios k=i+1,....j-1.

| 0 , si i >j
S(i,j) |
| min{ min.k=i+1,...j-1{S(i,k),S(k,j)}, C[i,j]} en otro caso.


Observación; la matriz de programación debe ser construida de abaajo hacia arriba.







Bueno yo he hecho para el apartado 1) este código que se lo he enseñado a la tía y me dice que esta bien, pero que la verdad no acabo de comprender puesto que siempre me sale la solución de una la primera diagonal...

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void construirMatriz(int **m,int tam);
void imprimirMatriz(int **m,int tam);
int minRecorrido(int **m,int i,int j);

int main(int argc,char **argv){
    int **m;
    int n,i,j,result,x;
    srand(time(0));
    printf("Tamanio:");
    scanf("%d",&n);
    fflush(stdin);
    m=(int**)malloc(sizeof(int*)*n);
    for(x=0;x<n;x++)
      m[x]=(int*)malloc(sizeof(int)*n);
    construirMatriz(m,n);
    imprimirMatriz(m,n);
    printf("Introduzca i(tenga en cuenta el tamaño de la matriz):");
    scanf("%d",&i);
    fflush(stdin);
    printf("Introduzca j(tenga en cuenta el tamaño de la matriz):");
    scanf("%d",&j);
    fflush(stdin);
    result=minRecorrido(m,i,j);
   
    /*if(m[i][j]<result)
       result=m[i][j];
    */
    printf("El coste menor para ir de %d a %d es de %d.",i,j,result);
    getchar();
}

void construirMatriz(int **m,int tam){
     int i,j;                     
     for(i=0;i<tam;i++){
         for(j=0;j<tam;j++){
             if(i>=j)
                m[i][j]=0;
             else
                m[i][j]=rand()%20;
         }
     }
}


void imprimirMatriz(int **m,int tam){
     int i,j;                     
     for(i=0;i<tam;i++){
         for(j=0;j<tam;j++)
             printf("%d\t",m[i][j]);
         printf("\n");
     }
}


int  minRecorrido(int **m,int i,int j){

    int k,result,min=99999;
    if(i>=j)
       return 0;
    if(j-1==i)
       return m[i][j];
    else{
        for(k=i+1;k<=j-1;k++){
            result=minRecorrido(m,i,k)+minRecorrido(m,k,j);
            if(result<min)
                min=result;
        }
        return min;
    }
}



Para el 2 no se como hacerlo , ella me ha planteado (hecho esto):

for(i=n-2;i>0;i++){
    for(j=i+1;j<n;j++){
       min=999999;
       for(k=i+1;k<j-1;k++){
          r=C[i,k]+C[k,j];
          if(r<min)
            min=r;
       }   
    }
}


Que creo que esta mal porque k va a valer lo mismo que j nunca va hacer la iteracion.

¿Me podeis dar ayudar?,comentar código , cualquier cosa es bien recibida

PD;No aparece bien la denicion recursiva del enunciado se supone que S(i,j) se abren llaves y aparcen los 2 casos
me sale la solución de una la primera diagonal...


Pocas pruebas has hecho,
Tamanio:4
0       9       6       11
0       0       5       9
0       0       0       5
0       0       0       0
Introduzca i(tenga en cuenta el tamaño de la matriz):1
Introduzca j(tenga en cuenta el tamaño de la matriz):3
El coste menor para ir de 1 a 3 es de 10.


2) Una funcion no recursiva que calcule S(i,j). En particular S(0,n-1). (Tecnica de programacion dinamica)

Con programación dinamica, no te estará pidiendo que uses una estructura dinámica? (pila, cola, lista, arbol, monticulo....)

Sino con solo bucles, juraría que no es posible resolverlo.
nu_kru escribió:Pocas pruebas has hecho,


Fijate que has puesto los puntos 1,3, por lo que te ha sumado el 5 de la coordenada (1,2) y el otro 5 de la coordenada (2,3)

nu_kru escribió:Con programación dinamica, no te estará pidiendo que uses una estructura dinámica? (pila, cola, lista, arbol, monticulo....)
Sino con solo bucles, juraría que no es posible resolverlo.


No esta pidiendo que sea con programación dimanica, es decir contruyendo una matriz y con los resultados obtenidos de los subproblemas, reutilizarlos, la cuestion es que el puto algoritmo se me atraganta.
pasteles escribió:
Fijate que has puesto los puntos 1,3, por lo que te ha sumado el 5 de la coordenada (1,2) y el otro 5 de la coordenada (2,3)

ups... pensaba que decias otra cosa. de todas formas el coste de 1,3 no es 9? salto directo... ahora miro el algoritmo
pasteles escribió:No esta pidiendo que sea con programación dimanica, es decir contruyendo una matriz y con los resultados obtenidos de los subproblemas, reutilizarlos, la cuestion es que el puto algoritmo se me atraganta.


Me ha picado el gusanillo, voy a pensar un ratejo y luego edito
Joder!!! Me acabo de dar cuenta que en wikipedia esta el ejercicio resuelto algoritmicamente. Llego a saberlo esto en el examen...pero quien coño se va a esperar que te pongan un examen en italia de algoritmos y el ejercicio esta resuelto en la wikipedia de españa. Bueno os pego el código y os pregunto la duda

FUNC Embarcaderos ( ↓ origen, destino, n: NATURAL, ↓ T: MATRIZ DE NATURAL): NATURAL
   Variables
       C: MATRIZ DE NATURAL
       i, j: NATURAL
   Inicio
       PARA i ← 1 HASTA n HACER
           C[i][i] ← 0
       FINPARA
       PARA i ← 1 HASTA n HACER
           PARA j ← 1 HASTA n HACER
               C[i][j] ← menorDeLosCandidatos(i, j, n, T, C)
           FINPARA
       FINPARA
       devolver C[n] [n]
   Fin




   FUNC menorDeLosCandidatos ( ↓ origen, destino, n: NATURAL, ↓ T, C: MATRIZ DE NATURAL): NATURAL
   Variables
       temp: NATURAL
   Inicio
       temp ← MAX_NATURAL
       PARA i ← origen+1 HASTA n HACER
           temp ← min(temp, T[origen][i] + C[i][destino]
       FINPARA
       devolver temp
   Fin



La definicion de la recursividad.

                 0   si i = j
C(i, j)=
           Min(T(i,k) + C(k,j), T(i,j))   si i < k <= j



La cosa es que en la funcion de menorcandidato no entiendo la línea

       temp ← MAX_NATURAL


de donde saca el valor MAX_NATURAL??


Os pongo el enlace a wikipedia. http://es.wikipedia.org/wiki/Programaci ... .C3.A1mica
Supongo que ese valor MAX_NATURAL al que se refiere, podrías sustituirlo por INT_MAX (o MAX_INT nunca recuerdo cual era exactamente) de la librería limits.h en C.
(mensaje borrado)
Normalmente, de forma dinámica se hace usando un Grafo y aplicándole dijsktra
nu_kru escribió:... Sino con solo bucles, juraría que no es posible resolverlo.


Siempre existe una alternativa iterativa para un algoritmo recursivo.
Wirth dixit.
8 respuestas