Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Notas Grafos
Notas Grafos
1. Grafos. 1
1.1. Busquedas 1
1.2. DAGs 3
1.3. Arbol de expansion Minima. 3
1.4. Caminos mas cortos. 4
1.5. Flujos en Redes (Network Flow). 4
1.6. Otros Problemas. 8
1.7. Teoria de Grafos. 8
2. Programacion Dinamica. 8
2.1. LCS. 8
2.2. LIS (nlogk). 8
2.3. Multiplicacion optima de matrices. 8
2.4. Edit Distance. 8
2.5. Coin Change. 9
2.6. Knapsack 0-1 (Mochila). 9
2.7. KMP (String Matching). 9
2.8. Problema del cartero chino (Chinese Postman Problem). 9
3. Estructuras de datos. 10
3.1. Hashing (para cadenas). 10
3.2. Estructura Union-Find. 10
3.3. Funcion para suma de dos strings. 11
3.4. Funcion para multiplicacion de dos strings. 11
3.5. BigInteger 11
4. Busqueda y Ordenamiento. 12
4.1. MergeSort 12
4.2. Busqueda Binaria. 12
5. Geometria. 12
5.1. Geometria Clasica. 12
5.2. Geometria Computacional. 14
6. Teoria de Numeros. 20
6.1. Aritmetica Modular 20
6.2. Exponenciacion rapida. 20
6.3. Factorizacion prima de un entero. 20
6.4. GCD Extendido 20
6.5. Criba de Eratostenes. 20
6.6. Funcion Phi de Euler (Numero de primos relativos a un numero). 21
6.7. Formulas y teoremas utiles 21
7. Combinatoria. 22
7.1. Combinaciones. 22
7.2. Resolucion de Recurrencias Lineales usando Exponenciacion de una matriz (QMatrix). 23
7.3. Conteo. 23
7.4. Formulas utiles. 23
7.5. Generacion Combinatoria 23
8. Otros. 23
1. Grafos.
1.1. Busquedas.
1.1.1. DFS y BFS.
int parent[MAX];
int seen[MAX];
2
}
return seen[t] != 0;
}
1.1.4. Ciclo de Euler. Existencia del ciclo de Euler. Un grafo tiene un ciclo de Euler si y solo si (i) esta
conectado y (2) todos sus vertices tienen grado par.
Existencia de un camino de Euler. Un grafo tiene un camino de Euler si y solo si (i) esta conectado y (2)
exactamente 2 de sus vertices tienen grado impar, los cuales constituyen el inicio y el n del camino.
Algoritmo para encontrar el camino de Euler. Encontrar ciclos de vertices disjuntos e irlos uniendo.
3
//////////////////////////// return v;
int tour(int x){ }
int w,v=x; //x contiene el vertice por el cual empieza el ciclo
bool stilledges=true; void find_euler(int x){
int v=x;
while(stilledges){ bool f=true; //solo se usa para imprimir bien
stilledges=false;
for(int i=0;i<MB;i++) while(tour(v)==v&&!S.empty()){
if(mat[v][i]) v=S.top();S.pop();
{w=i; if(f){
stilledges=true; cout< <x+1< <' '< <v+1< <endl;
break;} cout< <v+1< <' ';
if(stilledges){ }else{
S.push(v); cout< <v+1< <endl;
mat[v][w]--; if(!S.empty()) cout< <v+1< <' ';
mat[w][v]--; }
v=w; f=false;
} }
} }
1.2. DAGs.
while(!q.empty()){
int x=q.front(); q.pop();
//Aqui poner codigo para procesar el vertice (x)
for(int i=0;i<deg[x];i++){
indeg[adj[x][i]]--;
if(!indeg[adj[x][i]]) q.push(adj[x][i]);
}
}
1.5.3. s-t Minimum Cut. Max Flow Min Cut Teorema. El valor de un ujo maximo es igual a la capacidad
de un corte minimo.
1.5.4. All pairs-Minimum Cut. Se puede encontrar el minimo corte de un grafo jando un vertice y corriendo
n-1 ujos a partir de ese vertice a los demas, y tomando el minimo de estos.
Otra forma sin aplicar ujos, es mediante el algoritmo de Stoer-Wagner, el cual es el siguiente:
// run Stoer-Wagner
// Maximum number of vertices in the graph int best = MAXW * n * n;
#define NN 256 while( n > 1 )
// Maximum edge weight {
//(MAXW * NN * NN must fit into an int) // initialize the set A and vertex weights
#define MAXW 1000 a[v[0]] = true;
// Adjacency matrix and some internal arrays for( int i = 1; i < n; i++ ){
int g[NN][NN], v[NN], w[NN], na[NN]; a[v[i]] = false;
bool a[NN]; na[i - 1] = i;
int minCut( int n ) w[i] = g[v[0]][v[i]];
{ }
// init the remaining vertex set // add the other vertices
for( int i = 0; i < n; i++ ) v[i] = i; int prev = v[0];
6
Forma de uso: llenar matriz de adyacencia g y establecer n al numero de vertices del grafo.
while(1){
int u=-1; double mmin=INFD;
for(int i=0;i<n;i++) if(!seen[i]&&d[i]<mmin){
mmin=d[i];
u=i;
}
if(u==-1) break;
seen[u]=1;
for(int i=0;i<deg[u];i++){
int v=adj[u][i];
if(seen[v]) continue;
//-----------------------------------------------------
void init_pi(int s,int n){ //Bellman-Ford para maxcost-maxflow
for(int i=0;i<n;i++) pi[i]=INFD;
pi[s]=0;
for(int i=0;i<n-1;i++)
for(int j=0;j<n;j++)
for(int k=0;k<deg[j];k++)
if((f[j][adj[j][k]]<cap[j][adj[j][k]])&&
(pi[adj[j][k]]>pi[j]+cost[j][adj[j][k]]))
pi[adj[j][k]]=pi[j]+cost[j][adj[j][k]];
}
//------------------------------------------------------
int mcmf(int s,int t,int n, double &fcost,bool mincost){
memset(f,0,sizeof(f));
if(mincost) //Si es mincost entonces funcion de etiquetado=0
for(int i=0;i<n;i++) pi[i]=0;
else //Si es maxcost entonces inicializar con Bellman-Ford
init_pi(s,n);
Notas: - Si se quiere obtener el costo maximo, entonces antes de realizar el algoritmo se deben negar los
costos.
8
-El algoritmo anterior asume que si (u, v) ∈ E , entonces (v, u) ∈/ E , por lo que si se quieren representar
grafos no dirigidos, se debe dividir cada vertice en dos nuevos vertices, el primero al que se conectaran todas
las aristas que entran al vertice, al segundo se conectaran todas las aristas que salen del vertice, y ademas
se unen estos dos nuevos vertices con una arista dirigida del primero al segundo, con costo de 0 y capacidad
innita.
1.5.6. Stable Marriage Problem.
1.6. Otros Problemas.
1.6.1. Minimum Vertex Cover. Un vertex cover de un grafo no dirigido G=(V,E), es un subconjunto V' de
V que contiene al menos una de las terminaciones de una arista, el problema denominado minimum vertex
cover tree busca el vertex cover con el minimo numero de elementos, en grafos en general es un problema
NP.
Grafos Bipartitos (Teorema de Konig). En un grafo bipartito G=(V,E), la maxima cardinalidad de
cualquier matching iguala la minima cardinalidad de cualquier vertex cover de G. Es decir, si se quiere
encontrar el minimum vertex cover de cualquier grafo es suciente con encontrar el maximum matching del
grafo.
1.7. Teoria de Grafos. Formula de Euler.
V −E+F =2
Numero de arboles diferentes etiquetados.
N Ar = snn−s−1 , s numero de componentes conexas.
2. Programacion Dinamica.
for(int i=0;i<e;i++){
int a,b,c;
scanf("%d %d %d",&a,&b,&c); a--; b--;
res+=c;
deg[a]++;
deg[b]++;
floyd[a][b]<?=c;
floyd[b][a]<?=c;
}
int n2=0;
for(int i=0;i<n;i++)
if(deg[i]%2) lodd[n2++]=i;
ngen=n2;
printf("%d\n",res+solve((1< <n2)-1));
}
return 0;
}
3. Estructuras de datos.
3.3. Funcion para suma de dos strings. for (int i=l-1; i>=0; i--) {
string suma(string a, string b) sum = a[i] + b[i] - '0' - '0' + ac;
{ c[i] = (sum % 10) + '0';
int l = 1 + (a.length() > b.length() ? ac = sum / 10;
a.length() : b.length()); }
string c(l, '0'); while(c.length() > 0 && c[0] == '0')
a = string(l - a.length(), '0') + a; c.erase( c.begin() );
b = string(l - b.length(), '0') + b; return c;
int ac = 0, sum = 0; }
3.5. BigInteger.
3.5.1. C++.
3.5.2. Java.
//Performing Bitwise Operations with BigInteger
// Create via a string
BigInteger bi1 = new BigInteger("1234567890123456890");
// Create via a long
BigInteger bi2 = BigInteger.valueOf(123L);
bi1 = bi1.add(bi2);
bi1 = bi1.multiply(bi2);
bi1 = bi1.subtract(bi2);
bi1 = bi1.divide(bi2);
bi1 = bi1.negate();
int exponent = 2;
bi1 = bi1.pow(exponent);
//Parsing and Formatting a Big Integer into Binary, Octal, and Hexadecimal
BigInteger bi = new BigInteger("1023");
// Parse and format to binary
bi = new BigInteger("1111111111", 2); // 1023
String s = bi.toString(2); // 1111111111
// Parse and format to octal
bi = new BigInteger("1777", 8); // 1023
s = bi.toString(8); // 1777
// Parse and format to decimal
bi = new BigInteger("1023"); // 1023
s = bi.toString(); // 1023
// Parse and format to hexadecimal
12
4. Busqueda y Ordenamiento.
while(1){
if(l>u) return -1;
m=(l+u)/2;
if(arr[m]==t) return m;
else if(arr[m]<t) l=m+1;
else u=m-1;
}
}
5. Geometria.
5.1. Geometria Clasica.
5.1.1. Punto de Interseccion (Segmento - Segmento, Segmento - Linea, Linea - Linea).
bool SegSegInt(point a,point b,point c,point d,point p){
double s,t,num,denom;
denom=a[X]*double(d[Y]-c[Y])+b[X]*double(c[Y]-d[Y])+
d[X]*double(b[Y]-a[Y])+c[X]*double(a[Y]-b[Y]);
//Paralelos
if(denom==0.0) return false;
num=a[X]*double(d[Y]-c[Y])+c[X]*double(a[Y]-d[Y])+
d[X]*double(c[Y]-a[Y]);
s=num/denom;
num=-(a[X]*double(c[Y]-b[Y])+b[X]*double(a[Y]-c[Y])+
c[X]*double(b[Y]-a[Y]));
t=num/denom;
p[X]=a[X]+s*(b[X]-a[X]);
13
p[Y]=a[Y]+s*(b[Y]-a[Y]);
return (0.0<=s&&s<=1.0&&0.0<=t&&t<=1.0);
}
El codigo anterior funciona para la interseccion de dos segmentos (a,b) y (c,d), para interseccion de segmento
linea modicar la ultima condicion por:
return (0.0<=s&&s<=1.0);
Y para la interseccion linea-linea, smplemente regresar true.
Linea dada en forma de dos puntos (x0,y0) y (x1,y1) y el punto (x,y). La distancia es con signo,
d(P, L) = (y0 −y1√
)x+(x1 −x0 )y+(x0 y1 −x1 y0 )
2 2
(x1 −x0 ) +(y1 −y0 )
Linea implicita de la forma f(x,y)=ax+by+c=0.
d(P, L) = ax+by+c
√
a2 +b2
vector<double> vx(sx.begin(),sx.end());
vector<double> vy(sy.begin(),sy.end());
double res=0.0;
for(int i=0;i<nx-1;i++){
for(int j=0;j<ny-1;j++){
bool inrect=false;
for(int k=0;k<n&&!inrect;k++)
if(R[k].xi<=vx[i]&&vx[i+1]<=R[k].xf&&
R[k].yi<=vy[j]&&vy[j+1]<=R[k].yf)
inrect=true;
if(inrect) res+=(vx[i+1]-vx[i])*(vy[j+1]-vy[j]);
}
}
return res;
}
a
= sinb B = sinc C = 2 ∗ R
sin A b2 = a2 + c2 − 2ac cos B
a = b2 + c2 − 2bc cos A
2 c2 = a2 + b2 − 2ab cos C
5.1.7. Formulas utiles. Distancia Geodesica entre dos puntos (en la supercie de una esfera).
haversine(x)=(1.0-cos(x))/2.0
a = haversine(lat2 - lat1)
b = cos(lat1) * cos(lat2) * haversine(lon2 - lon1)
c = 2 * atan2(sqrt(a + b), sqrt(1 - a - b))
d = R * c
donde R, es el radio de la esfera (6378 km para la tierra), Importante: convertir las latitudes y longitudes a
radianes antes de aplicar la Formula. Longitud (este a oeste, 0 a 360◦ ). Latitud Norte (+90◦ ) a sur (-90◦ ).
Radio
√ del circulo inscrito en un traingulo de lados a,b,c.
s(s−a)(s−b)(s−c)
r= s donde s es el semiperimetro.
Radio del circulo que pasa por un triangulo de lados a,b,c.
abc
r= √
4 s(s−a)(s−b)(s−c)
Matriz de rotacion de puntos. Para rotar un punto (x,y) en θ grados, en el sentido counterclockwise con
centro
· en¸ el punto
· (0,0), multiplicar
¸· el punto por la siguiente matriz.
¸
xr cos θ − sin θ x
=
yr sin θ cos θ y
Formula
p de Heron , Area de triangulo a,b,c.
A = s(s − a)(s − b)(s − c)
5.2. Geometria Computacional.
5.2.1. Area de triangulo y funciones Left(), Collinear, Right (CounterClockwise Order), Dot.
typedef TipoPunto point[2];
#define X 0
#define Y 1
//Nota: regresa 2 veces el area del triangulo
//formado por los puntos a,b y c
TipoPunto Area2(point a,point b,point c){
return a[X]*(b[Y]-c[Y])-a[Y]*(b[X]-c[X])+(b[X]*c[Y]-b[Y]*c[X]);
}
bool Left(point a,point b,point c){
return Area2(a,b,c)>0;
}
bool Lefton(point a,point b,point c){
return Area2(a,b,c)>=0;
}
bool Collinear(point a,point b,point c){
return Area2(a,b,c)==0;
}
bool Right(point a,point b,point c){
return Area2(a,b,c)<0;
}
15
return ((Left(a,b,c))xor(Left(a,b,d)))&&
((Left(c,d,a))xor(Left(c,d,b)));
}
//Checar si un punto (c) esta en el interior de un segmento (a,b)
bool between(point a,point b,point c){
if(!Collinear(a,b,c)) return false;
5.2.11. Mínimo rectángulo encapsulador. Primero se tiene que calcular el ConvexHull. Y se usará los datos
de la pila resultante.
double smallestBoundingRectangle (int n)
{
/// Se toma cada elemento de la pila
double mmin = 0;
18
int vnum;
point v;
bool del;
};
poly P[MAXV][MAXP];
int nP[MAXV];
double adj[MAXV][MAXV];
TipoPunto dist(point a,point b){
TipoPunto dx=a[X]-b[X];
TipoPunto dy=a[Y]-b[Y];
return sqrt(dx*dx+dy*dy);
}
TipoPunto Dot(point a,point b){
return a[X]*b[X]+a[Y]*b[Y];
}
double dist_point_to_segment( point p, point a,point b,point pclose)
{
TipoPunto v[2]={b[X]-a[X],b[Y]-a[Y]};
TipoPunto w[2]={p[X]-a[X],p[Y]-a[Y]};
TipoPunto c1 = Dot(w,v);
if ( c1 <= 0 ){
pclose[X]=a[X];
pclose[Y]=a[Y];
return dist(p,a);
}
double c2 = Dot(v,v);
if ( c2 <= c1 ){
pclose[X]=b[X];
pclose[Y]=b[Y];
return dist(p,b);
}
double t = c1 / c2;
pclose[X]=a[X]+t*v[X];
pclose[Y]=a[Y]+t*v[Y];
return dist(p,pclose);
}
/// i y j son los poligonos del arreglo de poligonos P
/// el arreglo nP lleva el número de puntos
double minimumDistancePolygons(int a, int b)
{
double minima = INF;
point temp;
for (int i=0;i<nP[a];i++)
{
for (int j=0;j<nP[b];j++)
{
// Condicion acorde al problema
if ((b==0||b==1) && j==nP[b]-1)
break;
minima<?= dist_point_to_segment (P[a][i].v,P[b][j].v,P[b][(j+1)%nP[b]].v,temp);
}
}
for (int i=0;i<nP[b];i++)
{
for (int j=0;j<nP[a];j++)
{ // Condicion acorde al problema
if ((a==0||a==1) && j==nP[a]-1) break;
minima<?= dist_point_to_segment (P[b][i].v,P[a][j].v,P[a][(j+1)%nP[a]].v,temp);
}
}
return minima;
}
20
6. Teoria de Numeros.
6.1. Aritmetica Modular.
6.1.1. Modulo y division de un entero grande sobre un long long (s/n o s%n).
string coc;
long long modu=0;
for(int i=0;i<s.size();i++){
modu=(modu*10+s[i]-'0');
coc+=((modu/n)+'0');
modu%=n;
}
int ind=0;
while(ind<s.size()&&coc[ind]=='0') ind++;
coc=coc.substr(ind);
if(coc.empty()) coc="0";
flag[i]=true;
for (i=(L%2!=0);i<d;i+=2)
flag[i]=false;
for (i=3;i<=sqrt(U);i+=2) {
if (i>L && !flag[i-L])
continue;
j=L/i*i;
if (j<L) j+=i;
if (j==i) j+=i;
j-=L;
for (;j<d;j+=i)
flag[j]=false;
}
if (L<=1) flag[1-L]=false;
if (L<=2) flag[2-L]=true;
/* output the result */
for (i=0;i<d;i++) if(flag[i])
cout < < (L+i) < < " ";
cout < < endl;
}
6.7.1. Numero de divisores de un entero n. n es el numero con su factorizacion por primos. nd es el numero
de divisores.
n = pα 1 α2 αn
1 p2 ...pn
nd = (α1 + 1)(α2 + 1)...(αn + 1)
6.7.3. Ternas Pitagoricas. Las soluciones primitivas positivas de x2 + y 2 = z 2 con y par son x = r2 − s2 ,
y = 2rs, z = r2 + s2 donde r y s son enteros arbitrarios de paridad opuesta con r > s > 0 y (r,s) = 1.
j k j k j k
6.7.4. Division de factorial sobre un primo. f (n, p) = np + pn2 + pn3 + ...
22
6.7.7. Conjetura de Golbach. Todo numero par puede ser escrito como la suma de dos numeros primos (a
excepcion del 2).
6.7.8. Primeras cifras de n a la k.
x = k * log10(n)
mantisa(x) = x - floor(x)
signif = pow(10.0, mantisa(x)) * 100 // para obtener las 3 más significativas
7. Combinatoria.
7.1. Combinaciones.
7.1.1. C(n,k).
void div_by_gcd(long &a, long &b){
long g = gcd(a,b);
a /= g;
b /= g;
}
long C(int n, int k){
long num = 1;
long den = 1;
long tomult,todiv;
if(k > n/2)
k = n-k;
for(int i = k;i;i--){
tomult = n-k+i;
todiv = i;
div_by_gcd(tomult,todiv);
div_by_gcd(num,todiv);
div_by_gcd(tomult,den);
num *= tomult;
den * = todiv;
}
return num/den;
}
8. Otros.
Archivos en Java.
import java.io.*;
import java.util.*;
class test {
public static void main (String [] args) throws IOException {
// Use BufferedReader rather than RandomAccessFile; it's much faster
BufferedReader f = new BufferedReader(new FileReader("test.in"));
// input file name goes above
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("test.out")));
// Use StringTokenizer vs. readLine/split -- lots faster
StringTokenizer st = new StringTokenizer(f.readLine());
// Get line, break into tokens
int i1 = Integer.parseInt(st.nextToken()); // first integer
int i2 = Integer.parseInt(st.nextToken()); // second integer
out.println(i1+i2); // output result
out.close(); // close the output file
System.exit(0); // don't omit this!
}
}
// Para leer de la entrada estandar usar
24
return 0;
}
Codigo Miscelaneo.
GCD
int GCD(int a,int b) {if(a%b==0) return b; else return GCD(b,a%b);}
--------------------------------------------------------
Probar si un año es bisiesto
bool leap(int y) {
return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);}
--------------------------------------------------------
PI
PI = 2*acos(0);
--------------------------------------------------------