Segundo parcial de EDA Facultad de Informática de Valencia
Transcripción
Segundo parcial de EDA Facultad de Informática de Valencia
Segundo parcial de EDA Facultad de Informática de Valencia 3 de junio de 2008 – Duración 2 horas No olvides poner el nombre. No utilices lápiz ni tinta roja. Se piden siempre soluciones eficientes. Pregunta 1 (2 puntos) Dada la siguiente implementación de un grafo: struct a r i s t a { int v ; // v e r t i c e d e s t i n o float peso ; a r i s t a ∗ next ; }; class grafo { i n t numVert ; a r i s t a ∗∗L ; // l i s t a a d y a c e n c i a ... public : ... f l o a t c a p a c i d a d C o r t a d u r a ( bool ∗X) const ; // X v e c t o r t a l l a numVert }; Se define una cortadura en el grafo G=(V,A) como una partición (X, V − X) de los vértices del grafo. La capacidad de una cortadura se define: X cap(X, V − X) = peso(u, v) u∈X,v∈V −X Se pide implementar el método capacidadCortadura. Solucion: f l o a t g r a f o : : c a p a c i d a d C o r t a d u r a ( bool ∗X) const { f l o a t r e s u l =0.0 f ; f o r ( i n t v=0; v<numVert;++v ) i f (X[ v ] ) f o r ( const a r i s t a ∗ r=L [ v ] ; r ! = 0 ; r=r−>next ) i f ( ! X[ r−>v ] ) r e s u l += r−>p e s o ; return p e s o ; } Pregunta 2 (2 puntos) El algoritmo de Ford-Fulkerson procede de manera iterativa actualizando un grafo residual Gr asociado al grafo del cual queremos obtener su flujo máximo. Implementa una función que recibe el grafo G y un grafo residual Gr, ambos con N vértices, y comprueba si dicho grafo residual corresponde al grafo G. Los dos grafos vienen dados mediante matrices de adyacencia, donde cada posición indica una capacidad: bool g r a f o R e s i d u a l V a l i d o ( i n t ∗∗G, i n t ∗∗Gr , i n t N) ; Solucion: bool g r a f o R e s i d u a l V a l i d o ( i n t ∗∗G, i n t ∗∗Gr , i n t N) { f o r ( i n t i =0; i <N; ++i ) f o r ( i n t j=i ; j <N; ++j ) i f (G[ i ] [ j ]+G[ j ] [ i ] != Gr [ i ] [ j ]+Gr [ j ] [ i ] ) return f a l s e ; return true ; } Pregunta 3 (2.5 puntos) Queremos ir de la ciudad A a la ciudad B de la forma más barata posible. Cada tramo tiene un coste en gasolina y en autopista. Implementa el método buscarCamino que devuelva: el número de tramos del camino, el coste desglosado en gasolina, y en peajes, el peaje más caro de todos los utilizados en el camino. struct a r i s t a { // tramo int v ; // c i u d a d d e s t i n o d e l tramo f l o a t g a s o l i n a ; // c o s t e g a s o l i n a d e l tramo float peaje ; // c o s t e p e a j e d e l tramo a r i s t a ∗ next ; }; class grafo { i n t numVert ; a r i s t a ∗∗L ; // l i s t a a d y a c e n c i a ... public : ... void buscarCamino ( i n t o r i g e n , i n t d e s t i n o , int &numeroTramos , f l o a t &c o s t e G a s o l i n a , f l o a t &c o s t e P e a j e s , f l o a t &peajeMasCaro ) ; }; Solucion: void g r a f o : : buscarCamino ( i n t o r i g e n , i n t d e s t i n o , int &numeroTramos , f l o a t &c o s t e G a s o l i n a , f l o a t &c o s t e P e a j e s , f l o a t &peajeMasCaro ) { // v e c t o r e s n e c e s a r i o s para D i j k s t r a , r e c u p e r a n d o camino : f l o a t ∗D = new f l o a t [ numVert ] ; // d i s t a n c i a int ∗P = new i n t [ numVert ] ; // p r e d e c e s o r e s bool ∗F = new bool [ numVert ] ; // f i j a d o s f o r ( i n t v=0;v<numVert;++v ) { P [ v]= −1; F [ v]= f a l s e ; D[ v]=INFINITY ; } D[ o r i g e n ] = 0 ; while ( ! F [ d e s t i n o ] ) { // e l e g i m o s v e r t i c e a f i j a r : i n t a f i j a r = −1; f l o a t d i s t = INFINITY ; f o r ( i n t i =0; i <numVert ; ++i ) i f ( ! F [ i ] && D[ i ]<= d i s t ) { a f i j a r =i ; d i s t=D[ i ] ; } F [ a f i j a r ] = true ; // l o f i j a m o s y a c t u a l i z a m o s D y P f o r ( a r i s t a ∗ r=L [ a f i j a r ] ; r ! = 0 ; r=r−>next ) i f ( ! F [ r−>v ] && D[ r−>v ] > D[ a f i j a r ]+ r−>g a s o l i n a+r−>p e a j e ) { D[ r−>v ] = D[ a f i j a r ]+ r−>g a s o l i n a+r−>p e a j e ; P [ r−>v ] = a f i j a r ; } // c i e r r a i f } // c i e r r a w h i l e // r e c u p e r a r e l camino para c o n t e s t a r l o que nos p i d e n : numeroTramos = 0 ; c o s t e G a s o l i n a = c o s t e P e a j e s = peajeMasCaro = 0 . 0 f ; f o r ( i n t r e c o=d e s t i n o ; r e c o != o r i g e n ; r e c o=P [ r e c o ] ) { a r i s t a ∗ r ; // b u s c a r a r i s t a de P [ r e c o ] a r e c o f o r ( r = L [ P [ r e c o ] ] ; r−>v != r e c o ; r=r−>next ) ; numeroTramos += 1 ; c o s t e G a s o l i n a += r−>g a s o l i n a ; costePeajes += r−>p e a j e ; i f ( peajeMasCaro < r−>p e a j e ) peajeMasCaro = r−>p e a j e ; } // l i b e r a r r e c u r s o s : delete [ ] D; delete [ ] P ; delete [ ] F ; } Pregunta 4 (3.5 puntos) El rey Arturo desea designar N caballeros para su mesa redonda, para ello debe elegir entre M (M > N ) candidatos al puesto. Tras una audiencia, consigue elaborar una matriz simétrica de talla M × M , donde cada posición (i, j) indica si los caballeros i y j son leales entre si. Debes ayudar al rey Arturo completando el código siguiente para listar todos los conjuntos de candidatos que podrı́an conformar la mesa redonda. void p r o c e s a r S o l u c i o n ( i n t ∗v , i n t N) ; // YA IMPLEMENTADA void generaMesaRedonda ( i n t N, i n t M, bool ∗∗ l e a l e s , // m a t r i z M x M i n t ∗ s o l u c i o n , // v e c t o r t a l l a N i n t l o n g S o l , // l o n g i t u d s o l . p a r c i a l // l o que c o n s i d e r e s c o n v e n i e n t e ) { // COMPLETAR } i n t main ( i n t argc , char ∗∗ argv ) { // COMPLETAR l l a m a d a i n i c i a l , p u e d e s s u p o n e r que N,M y l a // m a t r i z l e a l e s han s i d o ya i n i c i a l i z a d o s return 0 ; } Solucion, una forma: bool prometedor ( bool ∗∗ l e a l e s , i n t ∗ s o l , i n t l o n g S o l , i n t c a n d i d a t o ) { f o r ( i n t i =0; i <l o n g S o l ; ++i ) i f ( ! l e a l e s [ c a n d i d a t o ] [ s o l [ i ] ] ) return f a l s e ; return true ; } void generaMesaRedonda ( i n t N, i n t M, bool ∗∗ l e a l e s , // m a t r i z M x M i n t ∗ s o l u c i o n , // v e c t o r t a l l a N i n t l o n g S o l ) { // l o n g i t u d s o l . p a r c i a l i f ( l o n g S o l == N) { p r o c e s a r S o l u c i o n ( s o l u c i o n ,N) ; } e l s e { // r a m i f i c a r i n t d e s d e = ( l o n g S o l == 0 ) ? 0 : s o l u c i o n [ l o n g S o l − 1 ] ; f o r ( i n t i=d e s d e ; i <M; ++i ) { // probamos c a n d i d a t o s i f ( prometedor ( l e a l e s , s o l u c i o n , l o n g S o l , i ) ) { solucion [ longSol ] = i ; generaMesaRedonda (N,M, l e a l e s , s o l u c i o n , l o n g S o l +1) ; } } } } i n t main ( i n t argc , char ∗∗ argv ) { ... generaMesaRedonda (N,M, l e a l e s , s o l u c i o n , 0 ) ; ... } Solucion, otra forma: void generaMesaRedonda ( i n t N, i n t M, bool ∗∗ l e a l e s , // m a t r i z M x M int ∗ s o l u c i o n , // v e c t o r t a l l a N int longSol , // l o n g i t u d s o l . p a r c i a l i n t ∗ c o n t L e a l e s ) { // v e c t o r t a l l a M i f ( l o n g S o l == N) { p r o c e s a r S o l u c i o n ( s o l u c i o n ,N) ; } e l s e { // r a m i f i c a r i n t d e s d e = ( l o n g S o l == 0 ) ? 0 : s o l u c i o n [ l o n g S o l − 1 ] ; f o r ( i n t i=d e s d e ; i <M; ++i ) { // probamos c a n d i d a t o s i f ( c o n t L e a l e s [ i ] == l o n g S o l ) { // e s prometedor solucion [ longSol ] = i ; // marcar : f o r ( i n t j =0; j <M;++ j ) i f ( l e a l e s [ i ] [ j ] ) c o n t L e a l e s [ j ]++; // l l a m a d a r e c u r s i v a : generaMesaRedonda (N,M, l e a l e s , s o l u c i o n , l o n g S o l +1, c o n t L e a l e s ) ; // desmarcar : f o r ( i n t j =0; j <M;++ j ) i f ( l e a l e s [ i ] [ j ] ) c o n t L e a l e s [ j ]−−; } } } } i n t main ( i n t argc , char ∗∗ argv ) { ... i n t ∗ c o n t L e a l e s = new i n t [M] ; f o r ( i n t i =0; i <M;++ i ) c o n t L e a l e s [ i ] = 0 ; i n t ∗ s o l u c i o n = new i n t [N ] ; generaMesaRedonda (N,M, l e a l e s , s o l u c i o n , 0 , c o n t L e a l e s ) ; ... } Existen otras formas de resolver el problema utilizando búsqueda con retroceso. En cualquiera de las dos soluciones propuestas se puede calcular un vector con el grado de cada caballero (número de personas con las que es leal) y usar ese grado para no ramificar por aquellos caballeros con un grado menor que N − 1.