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.

Documentos relacionados