Primer parcial de EDA Facultad de Informática de Valencia 7
Transcripción
Primer parcial de EDA Facultad de Informática de Valencia 7
Primer parcial de EDA Facultad de Informática de Valencia 7 de junio de 2007 – Duración 2 horas No olvides poner el nombre. No utilices lápiz ni tinta roja. Se piden siempre soluciones eficientes. Pregunta 1 (2.5 puntos) Sean dos vectores de enteros A y B, de talla n, n > 0, tal que A contiene una secuencia estrictamente decreciente y B contiene una secuencia estrictamente creciente. Sabemos que existe un i, 0 ≤ i < n tal que A[i] = B[i]. Por ejemplo, en los vectores: A 0 20 1 12 2 8 3 7 4 5 5 0 6 -1 7 -3 B 0 -7 1 -5 2 8 3 10 4 12 5 13 6 26 7 70 se cumple que A[2] = B[2]. Se pide: Una función “Divide y vencerás” recursiva que calcule en tiempo O(log n) el valor i para el cual A[i] = B[i]. El perfil de la función debe ser: i n t c o r t e ( i n t ∗A, i n t ∗B , i n t l , i n t r ) donde l y r indican respectivamente los lı́mites izquierdo y derecho de los vectores A y B entre los cuales se está realizando la búsqueda. Justifica adecuadamente el coste de la función escrita. ¿Cuál es la llamada inicial a la función? Importante: Se considerará incorrecta una función que realice una búsqueda de coste lineal. Solución i n t c o r t e ( i n t ∗A, i n t ∗B , i n t l , i n t r ) { i f ( l == r ) return l ; i n t m = ( l+r ) / 2 ; i f (A[m] == B [m] ) return m; i f (A[m] > B [m] ) return c o r t e (A, B , m+1 , r ) ; return c o r t e (A, B , l , m−1) ; } La llamada inicial a este algoritmo será: i n t c = c o r t e (A, B , 0 , n−1) ; El coste del algoritmo es claramente O(log n) puesto que estamos realizando básicamente un búsqueda dicotómica. La relación de recurrencia asociada a este algoritmo es la siguiente: ( cte, si n ≤ 1; T (n) = T (n/2) + θ(1), si n > 1 Donde n es r − l + 1. Podemos aplicar el teorema visto en clase para los valores a = 1, b = 2 y k = 0 porque a ≥ 1 y b > 1. Como a = bk el coste será O(nk log n) = O(log n). Pregunta 2 (3.5 puntos) Dada la siguiente implementación de un árbol binario: c l a s s nodo { public : int v a l o r ; nodo ∗ i z q , ∗ d e r ; }; c l a s s a r b o l { // á r b o l b i n a r i o public : nodo ∗ r a i z ; a r b o l ( ) { r a i z = 0 ; } ; // c o n s t r u c t o r ˜ arbol () ; . . . // o t r o s métodos bool e s a r b o l b i n a r i o ( ) ; // e j e r c i c i o de examen i n t n o d o s c o n u n h i j o ( ) ; // e j e r c i c i o de examen }; Implementa el método es_arbol_binario de la clase arbol que determine eficientemente si el árbol binario es un árbol binario de búsqueda. Solución bool nodo : : e s a r b o l b i n a r i o ( ) { i f ( ( i z q && i z q −>v a l o r > v a l o r ) | | ( d e r && der−>v a l o r < v a l o r ) ) return f a l s e ; i f ( i z q && ! i z q −>e s a r b o l b i n a r i o ( ) ) return f a l s e ; i f ( d e r && ! der−>e s a r b o l b i n a r i o ( ) ) return f a l s e ; return true ; } bool a r b o l : : e s a r b o l b i n a r i o ( ) { return ( ( r a i z ==0) | | r a i z −>e s a r b o l b i n a r i o ( ) ) ; } Implementa el método nodos_con_un_hijo de la clase arbol que cuente el número de nodos que tienen un solo hijo. Solución i n t nodo : : n o d o s c o n u n h i j o ( ) { int contador = 0 ; i f ( ( i z q && ! d e r ) | | ( ! i z q && d e r ) ) // c o n t a d o r ++; i f ( i z q ) c o n t a d o r += i z q −>n o d o s c o n u n i f ( d e r ) c o n t a d o r += der−>n o d o s c o n u n return c o n t a d o r ; } int a r b o l : : n o d o s c o n u n h i j o ( ) { return ( r a i z ==0) ? 0 : r a i z −>n o d o s c o n } también i f ( ( i z q !=0) ˆ ( d e r !=0) ) hijo () ; hijo () ; un hijo () ; Pregunta 3 (4 puntos) Tenemos una imagen en blanco y negro guardada en un fichero con el siguiente formato: 9 0 0 0 0 0 0 0 1 1 8 0 1 1 1 1 1 0 1 1 1 0 1 0 1 0 0 0 0 1 1 1 0 1 1 0 0 0 1 0 1 0 1 0 0 0 0 1 1 1 1 1 1 0 0 1 0 1 1 1 1 1 0 1 0 0 0 0 0 0 0 0 1 0 es decir, f ilas, columnas y una secuencia de f ilas × columnas valores 0 (blanco) ó 1 (negro). También dispones de una clase mfset sin rango ni compresión de caminos a la que puedes añadir nuevos métodos si lo deseas: c l a s s MFset { i n t ∗ mfset , n ; public : MFset ( i n t N) ; ˜MFset ( ) ; void merge ( i n t x , i n t y ) ; int f i n d ( int x ) ; }; MFset : : MFset ( i n t N) { n = N ; m f s e t = new in t [ n ] ; f o r ( i n t i = 0 ; i <n ; i ++) m f s e t [ i ] = i ; } Se pide realizar un programa en C++ que reciba el nombre del fichero por la linea de comandos y que: Muestre por salida estándar el número de regiones negras 4-conectadas. Una región negra 4-conectada es un grupo de pixels de color negro tal que podemos ir de cualquier pixel a otro en horizontal o vertical por pixels negros. El ejemplo de la figura tiene 4 componentes. Salve el mismo fichero guardando cada región negra 4-conectada con un color diferente (los colores son valores numéricos consecutivos: 1, 2, 3, 4, . . . (el 0 se reserva para el fondo blanco). Muestre por salida estándar cuántos pixels negros tiene la región negra 4-conectada más grande. Solución #include < i o s t r e a m > #include < f s t r e a m > #include < c s t d l i b > // para e x i t using namespace s t d ; c l a s s MFset { i n t ∗ mfset , n ; public : MFset ( i n t N) ; ˜MFset ( ) ; void merge ( i n t x , i n t y ) ; int f i n d ( int x ) ; void examen ( i n t ∗ ∗ p i x e l s , i n t & n u m r e g i o n e s , i n t & max negro , i n t f i l a s , i n t columnas ) ; }; MFset : : MFset ( i n t N) { n = N ; m f s e t = new in t [ n ] ; f o r ( i n t i = 0 ; i <n ; i ++) m f s e t [ i ] = i ; } MFset : : ˜ MFset ( ) { delete [ ] m f s e t ; } void MFset : : merge ( i n t x , i n t y ) { m f s e t [ f i n d ( y ) ] = f i n d ( x ) ; // Ponemos y como h i j o de x } i n t MFset : : f i n d ( i n t x ) { while ( m f s e t [ x ] ! = x ) x=m f s e t [ x ] ; return x ; } void MFset : : examen ( i n t ∗ ∗ p i x e l s , i n t & n u m r e g i o n e s , i n t & max negro , i n t f i l a s , i n t columnas ) { n u m r e g i o n e s = 0 ; max negro =0; i n t f , c , rep , c o n t ; // c a l c u l a m o s e l numero de r e g i o n e s f o r ( f = 0 ; f < f i l a s ; f ++) f o r ( c = 0 ; c<columnas ; c++) i f ( p i x e l s [ f ] [ c ]==1 && m f s e t [ f ∗ columnas+c]== f ∗ columnas+c ) // r e p r e s e n t a n t e n u m r e g i o n e s ++; // c a l c u l a m o s l o s r e p r e s e n t a n t e s i n t ∗ r e p r e s e n t a n t e s = new in t [ n u m r e g i o n e s ] ; r e p =0; f o r ( f = 0 ; f < f i l a s ; f ++) f o r ( c = 0 ; c<columnas ; c++) i f ( p i x e l s [ f ] [ c ]==1 && m f s e t [ f ∗ columnas+c]== f ∗ columnas+c ) { r e p r e s e n t a n t e s [ r e p ]= f ∗ columnas+c ; r e p++; } f o r ( r e p = 0 ; rep<n u m r e g i o n e s ; r e p++){ c o n t =0; f o r ( f = 0 ; f < f i l a s ; f ++) f o r ( c = 0 ; c<columnas ; c++) i f ( p i x e l s [ f ] [ c ]==1 && f i n d ( f ∗ columnas+c )==r e p r e s e n t a n t e s [ r e p ] ) { c o n t++; p i x e l s [ f ] [ c ]= r e p + 1 ; // c o l o r e a m o s } i f ( c o n t > max negro ) // miramos s i e s l a r e g i o n con mas p i x e l e s max negro=c o n t ; } delete [ ] r e p r e s e n t a n t e s ; } i n t main ( i n t argc , char ∗ ∗ argv ) { i f ( argc != 2) { c e r r << ”Uso : ” << argv [0] < < ” f i c h e r o ” << e n d l ; exit (0) ; } i f s t r e a m f l e o ( argv [ 1 ] ) ; if (! f leo ) { c e r r << ” E r r o r a l a b r i r ” << argv [1] < < e n d l ; exit (1) ; } i n t f i l a s , columnas , ∗ ∗ p i x e l s ; // suponemos que e l f i c h e r o t i e n e e l f o r m a t o adecuado f l e o >> f i l a s >> columnas ; // l e e m o s l a s d i m e n s i o n e s p i x e l s = new in t ∗ [ f i l a s ] ; f o r ( i n t f = 0 ; f < f i l a s ; f ++) p i x e l s [ f ] = new in t [ columnas ] ; f o r ( i n t f = 0 ; f < f i l a s ; f ++) // l e e m o s l o s p i x e l s f o r ( i n t c = 0 ; c<columnas ; c++) f l e o >> p i x e l s [ f ] [ c ] ; f l e o . close () ; // ahora c a l c u l a m o s l a s componentes 4− c o n e c t a d a s : MFset m( f i l a s ∗ columnas ) ; f o r ( i n t f =0; f < f i l a s ; f ++) // procesamos l a s f i l a s f o r ( i n t c =0; c<columnas ; c++) { // procesamos l a s columnas i n t pos=f ∗ columnas+c ; i f ( p i x e l s [ f ] [ c ]==1) { // estamos en un p i x e l n e gr o // h o r i z o n t a l i f ( c +1 < columnas && p i x e l s [ f ] [ c +1]==1) m. merge ( pos , pos +1) ; // v e r t i c a l i f ( f +1 < f i l a s && p i x e l s [ f + 1 ] [ c ]==1) m. merge ( pos , pos+columnas ) ; } } // ahora c a l c u l a m o s l o que nos p i d e n : i n t n u m r e g i o n e s , max negro ; m. examen ( p i x e l s , n u m r e g i o n e s , max negro , f i l a s , columnas ) ; c o u t << ”La imagen t i e n e ” << n u m r e g i o n e s << ” r e g i o n e s 4− c o n e c t a d a s ” << e n d l << ”La componente 4− c o n e c t a d a más grande t i e n e ” << max negro << ” p i x e l s ” << e n d l ; o f s t r e a m f e s c ( argv [ 1 ] ) ; f e s c << f i l a s << ’ ’ << columnas << e n d l ; f o r ( i n t f = 0 ; f < f i l a s ; f ++){ f o r ( i n t c = 0 ; c<columnas ; c++) f e s c << ’ ’ << p i x e l s [ f ] [ c ] ; f e s c << e n d l ; } f esc . close () ; return 0 ; }