conjunto3.cpp
// $Id$
/*
COMIENZO DE DESCRIPCION
Diversas operaciones con conjuntos:
flat: Escribir una funcion predicado
{\tt bool flat(vector< set<int> > \&sw, int n);}
que retorna verdadero si cada par de enteros (j,k) con 0<=j,k<n
esta contenido en al menos uno de los conjunto en sw.
es-neg: Escribir una funcion predicado
{\tt bool es_neg(set<int> \&A,set<int> \&B);} que retorna verdadero
si el conjunto B contiene exactamente los mismos elementos
que A, pero cambiados de signo.
en-todos: Escribir una funcion
predicado {\tt bool en\_todos(vector< set<int> > \&v)} que retorna
verdadero si existe al menos un elemento que pertenece a todos los
conjuntos v[j].
mediana: Escribir una funcion
{\tt int mediana(list<int> \&L)} que retorna la mediana de los
valores contenidos en la lista {\tt L}.
[Tomados en el 3er parcial del 24-jun-2004]
Keywords: conjunto
FIN DE DESCRIPCION */
#include <iostream>
#include <list>
#include <algorithm>
#include "../aedsrc/setl.h"
#include "./util.h"
using namespace std;
using namespace aed;
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>---:
//
// AUXILIARES
//
// Hace un vector random insertando N elementos al azar en [M1,M2)
// Guarda que el conjunto final puede tener menos de N elementos
// ya que varios de los elementos insertados pueden coincidir entre si.
void make_random_set(set<int> &s,int N,int M1, int M2) {
s.clear();
for (int j=0; j<N; j++) s.insert(M1+irand(M2-M1));
}
void make_random_set(set<int> &s,int N,int M) {
make_random_set(s,N,0,M);
}
// Imprime el conjunto
template <class T>
void prints (set <T> & S) {
typename set <T> :: iterator p ;
p = S.begin ();
while (p != S.end ()) cout << *p++ << " ";
cout << endl;
}
//---:---<*>---:---<*>---:- FLAT :---<*>---:---<*>---:---<*>---:
/* Escribir una funcion predicado bool disjuntos(v)
que verifica si todos los conjuntos dentro del vector
de conjuntos v[] son disjuntos
Se est\'a dise\~nando una red inerconectada por switches y se desea,
para reducir lo m\'as posible la \emph{latencia} entre nodos, que cada par
de nodos est\'e conectado en forma directa por al menos un switch.
Sabemos que el n\'umero de nodos es \verb+n+ y tenemos un
\verb+vector< set<int> > sw+ que contiene para cada switch el
conjunto de los nodos conectados por ese switch, es decir
\verb+sw[j]+ es un conjunto de enteros que representa el conjunto de
nodos inteconectados por el switch $j$. \\
\emph{ Consigna: }Escribir una funci\'on predicado
\verb+bool flat(vector< set<int> > &sw, int n);+
que retorna verdadero si cada par de enteros $(j,k)$ con $0\le j,k<
n$ est\'a contenido en al menos uno de los conjunto en \verb+sw[]+.
Por ejemplo, para
vector \verb+sw+ ser\'\i{}a
\begin{equation}
\text{\tt sw[0]} = \{0,1,2,3,4\},\ \
\text{\tt sw[1]} = \{0,1,5,6,7\},\ \
\text{\tt sw[2]} = \{2,3,4,5,6,7\}
\end{equation}
%
Por lo tanto \verb+flat(sw,8)+ debe retornar \verb+true+.
Por otra parte si tenemos
%
\begin{equation}
\text{\tt sw[0]} = \{0,2,3,4\},\ \
\text{\tt sw[1]} = \{0,1,5,7\},\ \
\text{\tt sw[2]} = \{2,3,5,6,7\}
\end{equation}
%
entonces los pares $(0,6)$, $(1,2)$, $(1,3)$, $(1,4)$, $(1,6)$,
$(4,5)$, $(4,6)$ y $(4,7)$ no est\'an conectados en forma
directa y \verb+flat(sw,8)+ debe retornar \verb+false+. \\
\emph{Sugerencia 1: } Recorrer todos los pares de valores $(j,k)$ y
para cada par recorrer todos los conjuntos en \verb+sw[]+ hasta
encontrar uno que contenga al par. \\
\emph{Sugerencia 2: } Puede ser de ayuda el escribir una funci\'on
auxiliar \verb+bool estan_conectados(sw,j,k)+.
*/
bool flat(vector< set<int> > &sw, int n) {
for (int j=0; j<n-1; j++) {
for (int k=j+1; k<n; k++) {
int l;
for (l=0; l<sw.size(); l++) {
if (sw[l].find(j)!=sw[l].end()
&& sw[l].find(k)!=sw[l].end()) break;
}
if (l==sw.size()) {
cout << "par (" << j << "," << k << ") no esta!!\n";
return false;
}
}
}
return true;
}
//---:---<*>---:---<*>---:- ES-NEG >---:---<*>---:---<*>---:---<*>---:
/*
Escribir una funci\'on predicado
\verb+bool es_neg(set<int> &A,set<int> &B);+ que retorna verdadero
si el conjunto \verb+B+ contiene exactamente los mismos elementos
que \verb+A+, pero cambiados de signo. Por ejemplo, si
$A=\{-5,-3,5,10\}$ y $B=\{-10,-5,3,5\}$ entonces \verb+es_neg(A,B)+
debe retornar \verb+true+. Mientras que si $A=\{-5,-3,2,10\}$ y
$B=\{-10,-5,4,5\}$, entonces debe retornar \verb+false+ ya que el
elemento 2 de $A$ y el 4 de $B$ no tienen su negativo en el otro
conjunto. \\
\emph{Estrategia 1: } Crear un conjunto temporario con los
negativos de $A$ y compararlo con $B$. \\
\emph{Estrategia 2: } Recorrer los elementos de $A$ y verificar que
su negativo est\'e en $B$ y viceversa.
*/
bool es_neg(set<int> &A,set<int> &B) {
set<int>::iterator p = A.begin();
if (A.size()!=B.size()) return false;
while (p!=A.end()) if (B.find(-*p++)==B.end()) return false;
return true;
}
//---:---<*>---:---<*>- EN-TODOS ----<*>---:---<*>---:---<*>---:
/*
Escribir una funci\'on
predicado \verb+bool en_todos(vector< set<int> > &v);+ que retorna
verdadero si existe al menos un elemento que pertenece a todos los
conjuntos \verb+v[j]+. Por ejemplo, si
%
\begin{equation}
\text{\tt v[0]} = \{0,2,3,4,5\},\ \
\text{\tt v[1]} = \{0,1,5,7\},\ \
\text{\tt v[2]} = \{2,3,5,6,7\}
\end{equation}
%
entonces \verb+en_todos(v)+ debe retornar \verb+true+ ya que 5 est\'a en los
tres conjuntos. Por el contrario, si
%
\begin{equation}
\text{\tt v[0]} = \{0,2,3,4,5\},\ \
\text{\tt v[1]} = \{0,1,7\},\ \
\text{\tt v[2]} = \{2,3,5,6,7\}
\end{equation}
%
entonces \verb+en_todos(v)+ debe retornar \verb+false+. \\
\emph{Sugerencia: } generar
el conjunto que es la intersecci\'on de todos los \verb+v[j]+ y
finalmente verificar si es vac\'\i{}o o no.
*/
bool en_todos(vector< set<int> > &v) {
int n = v.size();
if (!n) return false;
set<int> w = v[0]; // La interseccion de todos los conjuntos
set<int> tmp;
for (int j=1; j<n; j++) {
set_intersection(w,v[j],tmp);
if (tmp.empty()) return false;
w = tmp;
}
cout << "interseccion de todos: ";
prints(w);
return true;
}
// Igual que el anterior pero un poco mas eficiente. Usa punteros a
// conjuntos para w y tmp de manera que se ahorra una copia por
// iteracion.
bool en_todos2(vector< set<int> > &v) {
int n = v.size();
if (!n) return false;
set<int> w1 = v[0], w2; // La interseccion de todos los conjuntos
set<int> *w=&w1, *tmp=&w2, *aux;
for (int j=1; j<n; j++) {
set_intersection(*w,v[j],*tmp);
if (tmp->empty()) return false;
// Aca en vez de copiar los conjuntos
// hace un swap de los punteros
aux = w; w=tmp; tmp=aux;
}
cout << "interseccion de todos: ";
prints(*w);
return true;
}
//---:---<*>---:---<*>-- MEDIANA :---<*>---:---<*>---:---<*>---:
/*
Escribir una funci\'on
\verb+int mediana(list<int> &L);+ que retorna la mediana de los
valores contenidos en la lista \verb+L+. Recordemos que la mediana
de una serie de $n$ valores consiste en el valor que queda en la
posicion $n/2$ despu\'es de ordenarlos. Por ejemplo, si
$L=(3,2,4,-1,0)$ la mediana es 2. Asumir que todos los elementos en
$L$ son distintos. \\
\emph{Sugerencia: } Insertar los elementos en un conjunto temporario
$A$ y despu\'es buscar la posici\'on apropiada, recorri\'endolo con
un iterator. Recordemos que al iterar sobre un conjunto los
elementos aparecen en forma ordenada de menor a mayor.
*/
int mediana(list<int> &L) {
if (!L.size()) {
cout << "No se puede tomar la mediana de un conjunto vacio!!\n";
return -INT_MAX; // Como si fuera "- infinito"
}
set<int> A;
list<int>::iterator p = L.begin();
while (p!=L.end()) A.insert(*p++);
if (L.size()!=A.size()) {
cout << "Atencion: elementos repetidos en la lista!!\n";
}
int n = A.size();
set<int>::iterator q = A.begin();
for (int j=0; j<n/2; j++) q++;
return *q;
}
//---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>---:---<*>---:
int main () {
// verifica `flat'. Crea un vector de conjuntos aleatorio. los
// imprime y verifica si son disjuntos o no. Lo repite varias veces.
int N = 5;
vector< set<int> > v(N);
for (int k=0; k<10; k++) { // repite el experimento 10 veces
cout << "-----------\n";
for (int j=0; j<N; j++) {
make_random_set(v[j],12,10);
cout << "S_" << j << ": ";
prints(v[j]);
}
cout << "es flat ? " << (flat(v,10) ? "si" : "no") << endl;
}
cout << "-----------\n\n\n";
// verifica `es-neg'. Crea un vector con N conjuntos
// aleatorios e inserta los negativos de esos conjuntos.
// Despues hace un random_shuffle() del vector para
// desordenarlo y le va aplicando el es_neg() a cada par
// de sets en el vector.
N = 3;
v.clear();
v.resize(2*N);
for (int j=0; j<N; j++) {
make_random_set(v[j],10,-10,11);
set<int>::iterator p = v[j].begin();
while (p!=v[j].end()) v[j+1].insert(-*p++);
}
random_shuffle(v.begin(),v.end());
for (int j=0; j<2*N-1; j++) {
for (int k=j+1; k<2*N; k++) {
cout << "-----------\n";
cout << "set " << j << ": "; prints(v[j]);
cout << "set " << k << ": "; prints(v[k]);
cout << "es_neg(v[" << j << "],v[" << k << "]): "
<< (es_neg(v[j],v[k]) ? "si" : "no") << endl;
}
}
cout << "-----------\n\n\n";
// verifica `en-todos'. Crea un vector de conjuntos aleatorio
// y le aplica el en_todos(). Imprime la interseccion de
// todos los conjuntos. Prueba las dos
// versiones (en_todos() y en_todos2())
N = 6;
v.clear();
v.resize(N);
for (int k=0; k<20; k++) { // repite el experimento 20 veces
cout << "-----------\n";
for (int j=0; j<N; j++) {
make_random_set(v[j],10,10);
cout << "v[" << j << "]: ";
prints(v[j]);
}
cout << "en-todos(v)? " << (en_todos(v) ? "si" : "no") << endl;
cout << "en-todos2(v)? " << (en_todos2(v) ? "si" : "no") << endl;
}
// verifica `mediana'. Crea una lista aleatoria. Le aplica
// `mediana' y cuenta cuantos elementos menores que la mediana
// hay (deberian ser n/2-1).
list<int> L;
for (int k=0; k<20; k++) { // repite el experimento 20 veces
L.clear();
cout << "-----------\n";
randl(L,1000,11);
cout << "lista: "; printl(L);
int menores=0;
list<int>::iterator p = L.begin();
int med = mediana(L);
while (p!=L.end()) if(*p++ < med) menores++;
cout << "mediana: " << med << ", menores: " << menores << endl;
}
}
Generated by GNU Enscript 1.6.6.