Algorytm konkursowy

Algorytm konkursowy
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Witam, od jakiegoś czasu męczę się z pewnym problemem, mianowicie chodzi o program który na wejściu dostaje liczbę 0<<x<<2^32 i następnie potęguje liczbę 11 do potegi którą otrzymał na wejsciu. Program z wyniku potegowania zlicza wszystkie wystepujace w nim jedynki. Napisałem ten program, ale działa on poprawnie do momentu kiedy potega liczby 11 nie jest wieksza od 17. Gdy jest wieksza od 17 to w wyniku pojawiają się same zera. Ktoś mógłby mi pomóc ?

Załączam program:

Kopiuj
#include <stdio.h>
#include <conio.h>
#include <math.h>

int main(){

            char liczba[256];
            int i=0,j=0,potega=0;
            double wynik=0;

            printf("Witaj! Program policzy ilosc jedynek w dowolnej potedze liczby 11!\n\nPodaj potege:");
            scanf("%d",&potega);

            wynik=pow(11,potega);

            printf("\n\nOtrzymano liczbe %lf\n\n",wynik);

            sprintf(liczba,"%lf",wynik);    // KONWERSJA LICZBY DOUBLE DO TABLICY ZNAKOW ( KAZDA CYFRA TO JEDEN ZNAK!!! ) //

            for(i=0;i<potega+2;i++){

                                    if(liczba[i]==49) j++;        // W KODZIE ASCII ZNAK LICZBY 1 MA WARTOSC 49 //

                                    }

            printf("W liczbie wystepuje %d jedynek.",j);

            _getch();

            } 
_13th_Dragon
  • Rejestracja:prawie 20 lat
  • Ostatnio:11 dni
1

Zrób sobie tabelkę dla tych 11 potęg który możesz otrzymać i rozejrzyj się za regułą która te dane łączy.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Xitami
1,2,2,2,2,3,3,3,2,1,1,4,2,3,1,4,2,1,4,4,1,5,5,1,5,3,6,6,3,6,3,7,5,7,4,4,2,3,4,4,3,8,4,8,5,... widzisz tu jakąś regularność?
Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
1

11<sup>{2</sup>{32}} to spora liczba, ma ponad 4 giga cyfr.
11<sup>{297} nie mieści się w double, a już 11</sup>{16} policzysz źle.
pow() nie pomoże w niczym!

edytowany 4x, ostatnio: Xitami
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

No właśnie ... rozpisując ja żadnej regularności nie widzę... Nie mam żadnej koncepcji jak to wykonać

Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
1

samodzielne napisanie mnozenia dowolnie wielkiej liczby przez 11 nie jest trudne. na poczatek trzymaj w tablica odzienie każdą cyfre. później zmien na 8

Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

No ok, wsadzic osobno kazda cyfre do tablicy. Na poczatku w tablicy jest zatem 1,1 ,załóżmy ze potęgą jest 56 wiec mam wykonać pętle for, która przeleci 55 razy mnożąc i zapisując osobno każdą cyfrę. Jak wymnozyc poszczegolne cyfry tak aby powstał wynik zapisany tak ze kazda jego cyfra to osobne miejsce w tablicy ?

edytowany 1x, ostatnio: qwerty9
MA
  • Rejestracja:około 17 lat
  • Ostatnio:ponad 12 lat
1

Mnożenie składa się z dwóch części:
najpierw mnożysz każdą cyfrę przez 11 i zapisujesz w tym miejscu w którym była, np:
liczba:
5,7,2
mnożymy przez 11:
55,77,22
i następnie przesuwasz kolejne dziesiątki od prawej do lewej:

  1. 55, 77, 22
  2. 55, 77 + 2, 2
  3. 55, 79, 2
  4. 55 + 7, 9, 2
  5. 62, 9, 2
  6. 6, 2, 9, 2
    Przydadzą Ci się do tego operatory % oraz /
agilob
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Postów:148
0

Musisz wyjść poza standardowe biblioteki oferujące liczby.
Proponuję http://gmplib.org/
Gdzie poziom precyzji możesz ustawić ręcznie, a tutaj http://en.wikipedia.org/wiki/GNU_Multiple_Precision_Arithmetic_Library#Example jest przejrzysty przykład użycia.


Kiedyś miałem sen... że wszyscy ludzie zaczną używać tagów <code> i czytać błędy kompilatora...
edytowany 1x, ostatnio: agilob
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

@qwerty9, celem programu jest wyliczenie odpowiedniej potęgi liczy 11 i policzenie ile jest w niej jedynek, czy tylko policzenie ile jest jedynek?


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

policzenie ile jest jedynek w danej potędze 11
Sposób Marseel jest bardzo dobry, tylko czy można tworzyć tak duże tablice ?

edytowany 1x, ostatnio: qwerty9
KA
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 12 lat
0

Edit: nvm, moj blad, bzdury same tuta byly :)

edytowany 1x, ostatnio: kaboom
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Excel ma ten sam mankament co moj pierwotny program, mianowicie przy 16 potedze zaczyna pokazywac zera na koncu...

Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
0

mój skromny Atom 1.6 GHz potrzebował 41 sekund by policzyć, że 11^{100\ 000} ma 104 140 cyfr, w tym 10 190 jedynek.
program naiwny i samodzielny w 40 linijkach.

edytowany 1x, ostatnio: Xitami
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Napisałeś program tak, że każda cyfra to osobne miejsce w tablicy ?

Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
0

wcześniej zebrałem po 6, a teraz zrobiłem jak radziłem wcześniej czyli po 8 cyfr w int i mam czas 29 sekund.
czyli liczę w układzie nie dziesiętnym, za podstawę przyjąłem układ o podstawie 100 000 000
bo 99 999 999 * 11+99 999 999 "mieści" się w int

edytowany 1x, ostatnio: Xitami
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Twoje myślenie znacznie wykracza poza możliwości mojego umysłu, nie wiem o co chodzi :|

JA
  • Rejestracja:około 14 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Białystok
  • Postów:258
0

http://webcache.googleusercontent.com/search?q=cache:gVAcdWKGxL8J:main.edu.pl/user.phtml%3Fop%3Dlesson%26n%3D32+&cd=4&hl=pl&ct=clnk&gl=pl
Strona chwilowo padła, ale jak wróci to poczytaj sobie. W każdym razie słowo klucz - własna arytmetyka.

edytowany 1x, ostatnio: Jadeszek
Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
0

kiedy mnożysz na papierze, nie wstawiasz do słupka bezpośredniego wyniku mnożenia dwu cyfr, tylko bierzesz mod 10 (czyli najmniejszą cyfrę iloczynu tych cyfr) (oczywiście trzeba pamiętać o przeniesieniu)
a tu nie 10 tylko 100 000 000,
zamiast 8 bajtów mamy 4, ale pośrednich mnożeń jest 8 razy mniej.

Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Przepraszam za moje nieogarnianie ale dalej nie wiem o co Ci chodzi. Sam skleciłem cos takiego ale to nie ma prawa działać bo nie mozna takich tablic deklarować:

Kopiuj
#include <stdio.h>
#include <conio.h>
#include <math.h>

int main(){
            long int liczba[4294967297],potega,i=0,przesuniecie,pozostanie,rozbicie;

            printf("Podaj potege: ");
            scanf("%d",&potega);

            liczba[0]=1;
            liczba[1]=1;

            for(i=0,i<potega,i++){

                                    liczba[i]=liczba[i]*11;

                                    }

            for(i=potega-1;i>0;i--){

                                    przesuniecie=liczba[i]/10;
                                    pozostanie=liczba[i]%10;
                                    liczba[i]=pozostanie;
                                    liczba[i-1]=liczba[i-1]+przesuniecie;

                                    }

            rozbicie=liczba[0]%10;
            przesuniecie=liczba[0]/10;

            for(i=0;i<potega+1;i++){

                                    liczba[i+1]=liczba[0];

                                    }

            liczba[0]=przesuniecie;
            liczba[1]=rozbicie;

            _getch()

            }
 
edytowany 1x, ostatnio: qwerty9
AF
  • Rejestracja:prawie 18 lat
  • Ostatnio:około 2 miesiące
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Poddaję się.

merlinnot
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Wrocław
  • Postów:292
0

Och, to nie powinno być trudne, jeżeli wymyślisz sobie fajny sposób kodowania jak największej ilości cyfr w incie. Możesz to po prostu zrobić trójkątem pascala, odpowiednie wiersze to kolejne potęgi 11:

user image

Lub możesz pomyśleć o tym tak, że (11x) = (10+1)x i korzystać ze wzorów skróconego mnożenia:

user image

edytowany 2x, ostatnio: merlinnot
Zobacz pozostałe 13 komentarzy
merlinnot
Może warto zabrać się za coś prostszego? Np. pola kratowe to ciekawy temat (nie punkty, nie przejęzyczyłem się) :)
_13th_Dragon
Pewnie masz jeszcze za małe zęby aby ugryźć ten temat. Zacznij od rzeczy prostszych.
_13th_Dragon
@merlinnot, zwracam honor. Sam się zdziwiłem kiedy realizacja tego twojego pomysłu okazała się szybsza. A chciałem sprawdzić o ile będzie wolniejsza :D
Q9
Hm powiedz tylko czy dobrze rozumuje chcąc wsadzić tą każdą cyfre osobno do tablicy a potem je grupować ósemkami. Bo wpisywałem juz pojedynczo kazda cyfre ale nie potrafie stworzyc tak duzej tablicy
merlinnot
@_13th_Dragon Nie szkodzi, myślę, że jeżeli do wyliczania symbolu newtona użyć tego (z pełnym szacunkiem do autora) dziwactwa użytkownika dawidgarus, które jest piekielnie szybkie, można całkiem zgrabnie to napisać. Choć Xitami w konkursie zajmuje drugie miejsce, kod troszkę wolniejszy, ale zapis o wiele ładniejszy.
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Ale chcąc zrobić to trójkątem lub dwumianem to i tak muszę stworzyc ogromną tablice. Problem w tym ze nie potrafie takiej zrobic, lub robie to złym sposobem.
Muszę przecież każdą cyfre zapisac osobno prawda ?

edytowany 1x, ostatnio: qwerty9
merlinnot
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Wrocław
  • Postów:292
0

Kilka postów wyżej masz podany link do strony z pięknym opisem tego, jak należy się do tego zabrać, masz nawet napisane operatory. ctrl+c, ctrl+v. Implementacją tego, o czym mówił Xitami możesz spokojnie zająć się później, kiedy będziesz miał wstępnie działający algorytm.

msm
Administrator
  • Rejestracja:około 16 lat
  • Ostatnio:5 miesięcy
0

Widzę że się poddałeś, więc co mi tam, ja nic nie tracę, masz gotowca (znalezione gdzieś na dysku, nie pisane teraz).

Jakby co to nie mam pojęcia dlaczego, kiedy, jak, dla kogo i po co to kiedyś pisałem, ale prawdopodobnie to robiłem pijany o 4 w nocy patrząc na kod który jest lekkim WTF (szczególnie define i komentarz na początku - tak było w oryginale O_o)...

Tak czy inaczej, być może Ci w czymś pomoże, chociaż wątpię żeby otrzymanie gotowego kodu w czymkolwiek pomagało...

Kopiuj
using namespace std;

#define private public
// pure insane madness

#include <iostream>
#include <stdint.h>

typedef uint32_t chunk_t;
typedef uint64_t chunk_dbl_t;

class bigNum
{
private:
    static const chunk_t THRESHOLD = 1000; 

    chunk_t *chunks;
    size_t used_chunks;
    size_t allocated_chunks;

public:
    bigNum(int);
    bigNum(chunk_t *, int);
    bigNum operator*(const bigNum &);

    size_t estimateProductSize(const bigNum &, const bigNum &);
};

bigNum::bigNum(int value)
{
    this->chunks = new chunk_t[1];
    this->chunks[0] = value;
    this->used_chunks = 1;
    this->allocated_chunks = 1;
}

bigNum::bigNum(chunk_t *chunks, int numChunks)
{
    this->chunks = chunks;
    this->used_chunks = numChunks;
    this->allocated_chunks = numChunks;

    while(!this->chunks[this->used_chunks - 1])
    { this->used_chunks--; }
}

size_t bigNum::estimateProductSize(const bigNum &n1, const bigNum &n2)
{
    return n1.used_chunks + n2.used_chunks;
}

bigNum bigNum::operator*(const bigNum &other)
{
    size_t newSize = bigNum::estimateProductSize(*this, other);
    chunk_t *newChunks = new chunk_t[newSize];
    memset(newChunks, 0, newSize * sizeof(chunk_t));

    for(size_t i = 0; i < this->used_chunks; i++)
    {
        chunk_dbl_t carry = 0;
        for(size_t j = 0; j < other.used_chunks; j++)
        {
            chunk_dbl_t product = this->chunks[i] * other.chunks[j];
            product += newChunks[i + j] + carry;
      
            newChunks[i + j] = product % THRESHOLD;
            carry = product / THRESHOLD;
        }
        newChunks[i + other.used_chunks] = carry;
    }

    return bigNum(newChunks, newSize);
}

bigNum naivePow(int num, uint32_t pow)
{
    bigNum value = num;
    bigNum result = 1;

    for(uint32_t i = 0; i < pow; i++)
    {
        result = result * value;
    }

    return result;
}

bigNum basicFastPow(bigNum num, uint32_t pow)
{
    if (pow == 0) { return 1; }
    if (pow % 2 == 0) 
    { 
        bigNum tmp = basicFastPow(num, pow / 2);
        return tmp * tmp;
    }
    else
    {
        bigNum tmp = basicFastPow(num, (pow - 1) / 2);
        return num * tmp * tmp;
    }
}

int countOnes(const bigNum &n)
{
    int ct = 0;
    for(size_t i = 0; i < n.used_chunks; i++)
    {
        chunk_t chk = n.chunks[i];
        while(chk)
        {
            if (chk % 10 == 1) { ct++; }
            chk /= 10;
        }
    }
    return ct;
}

int main()
{
    int n;
    cin >> n;
    bigNum n1 = basicFastPow(11, n);
    cout << countOnes(n1) << endl; 
}
edytowany 5x, ostatnio: msm
Xitami
THRESHOLD=1000, w 32 bitach mieszczą się tylko 3 cyfry, wynik ma 5'963'663'365 bajtów, a ile jeszcze połknie potęgowanie?
msm
Przecież pisałem że ten kod to WTF, nie daję żadnej gwarancji za niego, ani nie uważam że jest dobry :> Po zrozumieniu co tu się dzieje można to przecież wszystko pozzmieniać...
Xitami
sprytnie napisane szybkie potęgowanie da się chyba zrobić tak, by potrzebowało tylko 2 razy tyle pamięci ile ma wynik (łącznie z wynikiem).
Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
0

potęgi 11 raczej palindromami nie są

Kopiuj
0       1
1       11
2       121
3       1331
4       14641
5       161051
6       1771561
7       19487171
8       214358881
9       2357947691

Jakoś nie podoba mnie mi się sposób trójkątno pascalowy.
(1+10)<sup>n=\sum_{k=0}</sup>{n}\left(\begin{array}{c}n\k\end{array}\right)10<sup>{n-k} nie mnożymy przez 10</sup>{n-k} to tylko "przesunięcie" przy sumowaniu, suma nie do n, tylko do około n/2, ale każdy krok to mnożenie i dzielenie długiej przez krótką,
w porównaniu do pojedynczego mnożenia długiej przez krótką
jakoś nie podoba mi się, niby operuje się liczbami krótszymi ale..., no nie podoba mi się

_13th_Dragon
@Xitami, nie zrozumiałeś pomysłu, tu chodzi o to że nie masz żadnego mnożenia tylko mnóstwo dodawań.
Xitami
dodając przybywa mi bit, mnożąc liczba bitów się podwaja, dodawanie miałoby być sprawniejsze? no i pamięć, wynik ma prawie 2 GBajty, a Pascal chciałby wektora takich liczb, kto to udźwignie?
merlinnot
@Xitami, od n=1 do n=k, a nie k=0 do k=n. Chodzi właśnie o to, że te ta dziesiątka do którejśtam jest łatwa w implementacji, bo po prostu n po k wpisujesz sobie ileśtam miejsc w lewo.
Xitami
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad rok
0

naiwne potęgowanie, podstawa systemu to 2^32, Atom'ek policzył:
9 sek. dla 100'000
36 sek. dla 200'000
80 sek dla 300'000
143 sek. dla 400'000
ile można się spodziewać dla 2'000'000'000 ? gdzieś około 114 lat :-)
moja potęga to unsigned int w[464317052]; to trochę mniej niż 2 GB.

dla porównania, coś nie naiwnego:

Kopiuj
PARI/GP (mechanika GMP)
 gp > 11^ 10 000 000;                 time =  3,829 ms.
 gp > 11^ 50 000 000;                 time = 25,297 ms.
 gp > 11^100 000 000;                 time = 50,297 ms.
 gp > 11^150 000 000;                 time = 1mn, 17,484 ms. 
 gp > 11^200 000 000;            *** _^s: length (lg) overflow
edytowany 2x, ostatnio: Xitami
Q9
  • Rejestracja:prawie 13 lat
  • Ostatnio:prawie 13 lat
  • Postów:14
0

Na początku nie wspomniałem iż językiem ma być c a nie c++.

merlinnot
  • Rejestracja:ponad 13 lat
  • Ostatnio:ponad 5 lat
  • Lokalizacja:Wrocław
  • Postów:292
0

To zamień sobie iostream na stdio.h i ciny na scanfy :)

_13th_Dragon
* oraz new na malloc a delete na free. To dużo skomplikowanej roboty, autor tematu z tym sobie nie poradzi.
merlinnot
Przepraszam, nie zauważyłem. Masz rację, może z jedną rzeczą dałby sobie radę, ale z DWIEMA?
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:2 minuty
0
marseel napisał(a):

Mnożenie składa się z dwóch części:
najpierw mnożysz każdą cyfrę przez 11 i zapisujesz w tym miejscu w którym była, np:
liczba:
<ciach>
Przydadzą Ci się do tego operatory % oraz /

a nie prościej dopisać 0 na końcu i dodać n? przyda się operator dodawania ;-)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.