elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Rompecabezas de Bitcoin, Medio millón USD en premios


  Mostrar Mensajes
Páginas: 1 2 3 4 5 6 7 [8] 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
71  Programación / Ejercicios / Re: Retos C/C++ en: 3 Octubre 2010, 16:52 pm
Si no recuerdo mal, la función strstr realiza la comprovación a lo bestia, es decir, si tenemos una string de n carácteres y queremos buscar en ella otra de m, para cada carácter de la primera mira si los m - 1 siguientes coinciden, quedando así un coste de O(nm).

Por si a alguien le interesa, existen algoritmos más eficientes para realizar esto, que consiguen costes de O(n + m), es decir, lineales sobre la longitud de las strings, como por ejemplo Knuth-Morris-Pratt.
72  Foros Generales / Foro Libre / Re: [Math] Ecuaciones con 3 incognitas en: 15 Septiembre 2010, 23:41 pm
El sistema se puede resolver perfectamente por Gauss que es lo que supongo que estás haciendo:
Código:
2   14   -4   -2
-4   -3   1   8
3   -5   6   7
f1 = f1/2 (por simplificar)
Código:
1   7   -2   -1
-4   -3   1   8
3   -5   6   7
f2 = f2 + 4f1
f3 = f3 -3f1
Código:
1   7   -2   -1
0   25   -7   4
0   -26   12   10
f3 = f3/2 (por simplificar)
Código:
1   7   -2   -1
0   25   -7   4
0   -13   6   5
f3 = 6f2 + 7f3
Código:
1   7   -2   -1
0   25   -7   4
0   59   0   59

Por lo tanto, y = 1, z = 3 y x = -2.
73  Programación / Ejercicios / Re: Retos C/C++ en: 13 Septiembre 2010, 20:31 pm
He reaprovechado un código que hice hace un tiempo que multiplica usando Karatsuba, por lo que el código es largo y feo. Si alguien lo prefiere dejo una versión nueva y más legible sin usar Karatsuba. De hecho, Karatsuba sólo se usa si los dos números a multiplicar son suficiente grandes (unos 100 dígitos) en mi código, pero lo dejo por si a alguien le interesa.
Código
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. using namespace std;
  5.  
  6. typedef vector<long long> VL;
  7.  
  8. VL mult(VL& a, int i1, int f1, VL& b, int i2, int f2) {
  9.    if (i1 > f1 or i2 > f2) return VL(1,0);
  10.    if (f1 >= a.size()) return mult(a, i1, a.size() - 1, b, i2, f2);
  11.    if (f2 >= b.size()) return mult(a, i1, f1, b, i2, b.size() - 1);
  12.    if (i1 >= a.size() or i2 >= b.size()) return VL(1,0);
  13.    int n = f1 - i1 + 1, m = f2 - i2 + 1;
  14.    VL c(max(n,m)*2 + 1, 0);
  15.    for (int i = i1; i <= f1; ++i) {
  16.        for (int j = i2; j <= f2; ++j) {
  17.            c[i - i1 + j - i2] += (a[i]*b[j]);
  18.            c[i - i1 + j - i2 + 1] += (c[i - i1 + j - i2]/1000000000);
  19.            c[i - i1 + j - i2] %= 1000000000;
  20.        }
  21.    }
  22.    int pos = c.size() - 1;
  23.    while (pos > 0 and c[pos--] == 0) c.pop_back();
  24.    return c;
  25. }
  26.  
  27. VL suma(VL& a, int i1, int f1, VL& b, int i2, int f2) {
  28.    if (i1 > f1 or i1 >= a.size()) {
  29.        VL cero(1,0);
  30.        return suma(cero, 0, 0, b, i2, f2);
  31.    }
  32.    if (i2 > f2 or i2 >= b.size()) {
  33.        VL cero(1, 0);
  34.        return suma(a, i1, f1, cero, 0, 0);
  35.    }
  36.    if (f1 >= a.size()) return suma(a, i1, a.size() - 1, b, i2, f2);
  37.    if (f2 >= b.size()) return suma(a, i1, f1, b, i2, b.size() - 1);
  38.    int n = f1 - i1 + 1, m = f2 - i2 + 1;
  39.    VL c(n + m + 2, 0);
  40.    int i = i1, j = i2, k = 0;
  41.    while (i <= f1 and j <= f2) {
  42.        c[k] += (a[i] + b[j]);
  43.        c[k + 1] += (c[k]/1000000000);
  44.        c[k] %= 1000000000;
  45.        ++i; ++j; ++k;
  46.    }
  47.    while (i <= f1) {
  48.        c[k] += a[i];
  49.        c[k + 1] += (c[k]/1000000000);
  50.        c[k] %= 1000000000;
  51.        ++i; ++k;
  52.    }
  53.    while (j <= f2) {
  54.        c[k] += b[j];
  55.        c[k + 1] += (c[k]/1000000000);
  56.        c[k] %= 1000000000;
  57.        ++j; ++k;
  58.    }
  59.    int pos = c.size() - 1;
  60.    while (pos > 0 and c[pos--] == 0) c.pop_back();
  61.    return c;
  62. }
  63.  
  64. VL resta(VL& a, int i1, int f1, VL& b, int i2, int f2) {
  65.    VL c;
  66.    c = a;
  67.    for (int i = i2; i <= f2; ++i) {
  68.        c[i] -= b[i];
  69.        while (c[i] < 0) {
  70.            c[i] += 1000000000;
  71.            c[i + 1]--;
  72.        }
  73.    }
  74.    int pos = c.size() - 1;
  75.    while (pos > 0 and c[pos--] == 0) c.pop_back();
  76.    return c;
  77. }
  78.  
  79. VL karatsuba(VL& a, int i1, int f1, VL& b, int i2, int f2) {
  80.    if (i1 > f1 or i2 > f2) return VL(1,0);
  81.    if (f1 >= a.size()) return karatsuba(a, i1, a.size() - 1, b, i2, f2);
  82.    if (f2 >= b.size()) return karatsuba(a, i1, f1, b, i2, b.size() - 1);
  83.    if (i1 >= a.size() or i2 >= b.size()) return VL(1,0);
  84.    int p = f1 - i1 + 1, m = f2 - i2 + 1;
  85.    if (min(p, m) <= 10) return mult(a, i1, f1, b, i2, f2);
  86.    int n = max(p, m);
  87.    VL c1, c2, c3, x, y;
  88.    int mit = n/2;
  89.    c1 = karatsuba(a, i1 + mit, f1, b, i2 + mit, f2);
  90.    c3 = karatsuba(a, i1, i1 + mit - 1, b, i2, i2 + mit - 1);
  91.    x = suma(a, i1, i1 + mit - 1, a, i1 + mit, f1);
  92.    y = suma(b, i2, i2 + mit - 1, b, i2 + mit, f2);
  93.    c2 = karatsuba(x, 0, x.size() - 1, y, 0, y.size() - 1);
  94.    c2 = resta(c2, 0, c2.size() - 1, c1, 0, c1.size() - 1);
  95.    c2 = resta(c2, 0, c2.size() - 1, c3, 0, c3.size() - 1);
  96.    VL res(2*n + 3, 0);
  97.    for (int i = 0; i < c1.size(); ++i) {
  98.        res[i + 2*mit] += c1[i];
  99.        res[i + 2*mit + 1] += (res[i + 2*mit]/1000000000);
  100.        res[i + 2*mit] %= 1000000000;
  101.    }
  102.    for (int i = 0; i < c2.size(); ++i) {
  103.        res[i + mit] += c2[i];
  104.        res[i + mit + 1] += (res[i + mit]/1000000000);
  105.        res[i + mit] %= 1000000000;
  106.    }
  107.    for (int i = 0; i < c3.size(); ++i) {
  108.        res[i] += c3[i];
  109.        res[i + 1] += (res[i]/1000000000);
  110.        res[i] %= 1000000000;
  111.    }
  112.    int pos = res.size() - 1;
  113.    while (pos > 0 and res[pos--] == 0) res.pop_back();
  114.    return res;
  115. }
  116.  
  117. string str(long long x) {
  118.    string s;
  119.    do {
  120.        s += char(x%10 + '0');
  121.        x /= 10;
  122.    } while(x > 0);
  123.    reverse(s.begin(), s.end());
  124.    return s;
  125. }
  126.  
  127. int main() {
  128.    int n;
  129.    cin >> n;
  130.    VL res(1,1);
  131.    for (int i = 1; i <= n; ++i) {
  132.        VL a(1,i);
  133.        VL c;
  134.        c = karatsuba(a, 0, a.size() - 1, res, 0, res.size() - 1);
  135.        res = c;
  136.    }
  137.    cout << res[res.size() - 1];
  138.    for (int i = res.size() - 2; i >= 0; --i) {
  139.        string s = str(res[i]);
  140.        cout << string(9 - s.size(), '0') << s;
  141.    }
  142.    cout << endl;
  143. }
  144.  

Ahora pasemos al reto de Og. y a ver si alguien se anima, que es una dinámica sencillita.
74  Programación / Programación General / Re: Inicializar matrices en Floyd en: 28 Agosto 2010, 19:38 pm
Tal y como he puesto el código, si M es la matriz de antecesores y u, v son dos nodos cualquiera tales que existe un camino entre ellos (la distancia mínima entre ellos tras hacer Floyd-Warshall no es INF), M[ u][ v] indica el penúltimo nodo del camino mínimo entre u y v. Por ejemplo, si M[ u][v] vale k, significa que el menor camino de u a v será:
u -> (camino entre u y k) -> k -> v.

Y dicho camino entre u y k naturalmente será el mínimo camino entre u y k, por lo que volviendo a consultar la matriz de antecesores podemos ir creando el camino, hasta llegar al origen. La siguiente función, te devolvería el camino mínimo entre s y t con el código anterior que puse:
Código
  1. void camino(int s, int t, vector<vector<int> >& A) {
  2.    if (t != s) camino(s, A[s][t], A);
  3.    cout << t << " ";
  4. }

Por ejemplo, en el caso de un grafo más complejo como tú decías, si tienes el siguiente grafo (pongo la entrada como la recibe mi programa):
Código:
5 7
0 1 1
0 2 4
0 3 3
1 3 1
2 3 1
2 4 1
3 4 5

Es evidente que el camino mínimo entre los nodos 0 y 4 tiene coste 4 y pasa por todos los nodos. Si llamas a la función que te he puesto:
Código
  1. cout << "Camino de nodo 0 a nodo 4" << endl;
  2. camino(0, 4, A);

Devuelve la siguiente salida:
Código:
Camino de nodo 0 a nodo 4
0 1 3 2 4

Que es efectivamente el camino mínimo entre 0 y 4.

75  Programación / Ejercicios / Re: Retos C/C++ en: 27 Agosto 2010, 04:50 am
Reto #14
Como aún no he mirado los de este año, os dejo uno de la IOI del año pasado, a mi opinión, el más fácil de todos y con diferencia. Es bastante asequible.
http://www.ioi2009.org/GetResource?id=1271
76  Programación / Ejercicios / Re: Retos C/C++ en: 27 Agosto 2010, 03:58 am
Si tienes que consultar una lista es muy lento, la idea es usar un vector, para, por ejemplo, el primer millón de números. Obviamente se pasará de ese límite calculando ciertos números, para esos simplemente si ocurre repetiré los cálculos, puesto que no tenemos memoria infinita. Así al menos el intervalo completo [1, 1000000] lo hace de forma instantánea el siguiente programa (aunque repita cálculos si sale del rango):
Código
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. typedef long long ll;
  6.  
  7. ll f(ll n, vector<ll>& v) {
  8.    if (n == 1) return 1;
  9.    if (n >= v.size()) return 1 + ((n%2 == 1)?f(3*n + 1, v):f(n/2, v));
  10.    if (v[n] == -1) v[n] = 1 + ((n%2 == 1)?f(3*n + 1, v):f(n/2, v));
  11.    return v[n];
  12. }
  13.  
  14. int main() {
  15.    vector<ll> v(1000000, -1);
  16.    ll a, b;
  17.    while (cin >> a >> b) {
  18.        ll res = 0;
  19.        for (ll i = min(a,b); i <= max(a,b); ++i) res = max(res, f(i, v));
  20.        cout << a << " " << b << " " << res << endl;
  21.    }
  22. }

De hecho esto sería una manera de resolver el problema usando memoization.

Para poder guardar todos los valores, ya que un vector no se puede usar (demasiada memoria) y una lista como tú decías es demasiado lenta (hay que recorrerla entera en el peor caso, coste lineal), la mejor manera que se me ocurre es usar un árbol binario balanceado que permita consultar si está calculado (y su valor) en tiempo logarítmico. Estos están implementados en los contenedores map de la STL de C++. En este problema en concreto no sé qué sería más rápido, si guardar todo con maps aumentando el coste de cada consulta o bien hacer cada consulta instántanea consultando un vector a costa de repetir los cálculos de números fuera del rango del vector.
77  Programación / Ejercicios / Re: Retos C/C++ en: 27 Agosto 2010, 03:20 am
La gracia es que sea más rápido, si no mal vamos. Simplemente guarda lo que hayas calculado una vez. Cada vez que pases por un número, antes de calcularlo mira si ya está hecho.
78  Programación / Ejercicios / Re: Retos C/C++ en: 27 Agosto 2010, 02:56 am
Si tu intervalo es el [1, 10], por ejemplo cuando mires el 3 pasarás por el 10, que luego volverás a calcular cuando llegues al 10. Lo que comentaba era evitar estas repeticiones de cálculos, puesto que si el intervalo es grande (según el enunciado los números del intervalo pueden llegar a 1000000), la diferencia es notoria.
79  Programación / Ejercicios / Re: Retos C/C++ en: 27 Agosto 2010, 02:38 am
No entiendo del todo el código porque no conozco el lenguaje, pero por lo que veo vas de uno en uno dentro del rango y vas haciendo el algoritmo hasta acabar. Hay una manera de hacerlo mucho más rápido.

Como pista, intenta no calcular los pasos para ningún número más de una sola vez ;)
80  Programación / Ejercicios / Re: Retos C/C++ en: 25 Agosto 2010, 18:21 pm
Según las normas tras tres días cualquiera puede poner otro reto, mejor que lo ponga otro, que yo puse este último con intención de que fuera muy sencillo...
Páginas: 1 2 3 4 5 6 7 [8] 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines