Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[c++] Zadanie SPOJ JLITOSL - Liczba na słowo

Ostatnio zmodyfikowano 2020-03-12 17:43
Autor Wiadomość
Biedrzyk
Temat założony przez niniejszego użytkownika
[c++] Zadanie SPOJ JLITOSL - Liczba na słowo
» 2020-02-17 21:02:47
Witam,
zabrałem się za zadnie ze SPOJ-a JLITOSL - Liczba na słowo, https://pl.spoj.com/problems/JLITOSL/.

Jaś zaczął pracować w dziale firmy odpowiedzialnym za finanse. Do jego codziennych obowiązków należy wypełnianie przelewów pocztowych za różnego rodzaju płatności. Po kilku dniach zaczął odczuwać zniechęcenie, gdy po raz setny musiał na przelewie wypisywać słownie kwotę.

Pomoż Jasiowi i napisz program, który będzie zamieniał liczbę na jej zapis słowny.
Wejście

W pierwszym wierszu podana jest liczba testów t do wykonania (liczba naturalna z przedziału 1..1000). W następnych t wierszach liczba naturalna z przedziału 1..1012.
Wyjście

Na wyjściu powinny być wyświetlane w osobnych wierszach odpowiedniki liczb naturalnych podanych na wejściu w zapisie słownym (w wyrazach nie używamy polskich znaków). W zapisie należy użyć następujących skrótów: tys. - tysiąc, mln. - milion, mld. - miliard, bln. - bilion.
Przykład

Wejście:
5
1
12
345
1459
123456789

Wyjście:
jeden
dwanascie
trzysta czterdziesci piec
jeden tys. czterysta piecdziesiat dziewiec
sto dwadziescia trzy mln. czterysta piecdziesiat szesc tys. siedemset osiemdziesiat dziewiec


Kombinuję z mapą i na razie stoję w tym miejscu - jestem dopiero przy tysiącach a już liczba if'ów jest już duża a gdzie mi jeszcze do większych liczb. Pytanie czy jednak da się to trochę ulepszyć - nie chcę przeginać i zapętlić się w tych ifach.

C/C++
#include <iostream>
#include <string>
#include <map>

using namespace std;

int dziesiatki( int liczba )
{
    liczba =(( liczba / 10 ) * 10 );
   
    return liczba;
}

int setki( int liczba )
{
    liczba =(( liczba / 100 ) * 100 );
   
    return liczba;
}

int tysiace( int liczba )
{
    liczba =( liczba / 1000 );
   
    return liczba;
}

int main()
{
    map < int, string >::reverse_iterator ritr;
    map < int, string > inWords;
    inWords[ 0 ] = "zero";
    inWords[ 1 ] = "jeden";
    inWords[ 2 ] = "dwa";
    inWords[ 3 ] = "trzy";
    inWords[ 4 ] = "cztery";
    inWords[ 5 ] = "piec";
    inWords[ 6 ] = "szesc";
    inWords[ 7 ] = "siedem";
    inWords[ 8 ] = "osiem";
    inWords[ 9 ] = "dziewiec";
    inWords[ 10 ] = "dziesiec";
    inWords[ 11 ] = "jedenascie";
    inWords[ 12 ] = "dwanascie";
    inWords[ 13 ] = "trzynascie";
    inWords[ 14 ] = "czternascie";
    inWords[ 15 ] = "pietnascie";
    inWords[ 16 ] = "szesnascie";
    inWords[ 17 ] = "siedemnascie";
    inWords[ 18 ] = "osiemnascie";
    inWords[ 19 ] = "dziewietnascie";
    inWords[ 20 ] = "dwadziescia";
    inWords[ 30 ] = "trzydziesci";
    inWords[ 40 ] = "czterdziesci";
    inWords[ 50 ] = "piecdziesiat";
    inWords[ 60 ] = "szczescdziesiat";
    inWords[ 70 ] = "siedemdziesiat";
    inWords[ 80 ] = "osiemdziesiat";
    inWords[ 90 ] = "dziewiecdziesiat";
    inWords[ 100 ] = "sto";
    inWords[ 200 ] = "dwiescie";
    inWords[ 300 ] = "trzysta";
    inWords[ 400 ] = "czterysta";
    inWords[ 500 ] = "piecset";
    inWords[ 600 ] = "szescset";
    inWords[ 700 ] = "siedemset";
    inWords[ 800 ] = "osiemset";
    inWords[ 900 ] = "dziewiecset";
   
    int liczba = 0, nowa = 0, mniejsza = 0, nowa2 = 0, mniejsza2 = 0, nowa3 = 0, mniejsza3 = 0;
    cin >> liczba;
   
    for( map < int, string >::reverse_iterator ritr = inWords.rbegin(); ritr != inWords.rend(); ritr++ )
    {
        if( liczba == ritr->first )
        {
            cout << ritr->second;
        }
        if(( liczba > 20 ) &&( liczba < 100 ) &&( liczba != ritr->first ) )
        {
            mniejsza = dziesiatki( liczba );
            nowa = liczba % 10;
           
            if( nowa == ritr->first )
            {
                cout << ritr->second << " ";
            }
            if( mniejsza == ritr->first )
            {
                cout << ritr->second << " ";
            }
        }
        if(( liczba > 100 ) &&( liczba < 1000 ) &&( liczba != ritr->first ) )
        {
            mniejsza2 = setki( liczba );
            nowa3 = liczba - mniejsza2;
            nowa2 = dziesiatki( nowa3 );
            mniejsza3 = nowa3 - nowa2;
           
            if( nowa2 == ritr->first )
            {
                cout << ritr->second << " ";
            }
            if( mniejsza2 == ritr->first )
            {
                cout << ritr->second << " ";
            }
            if( nowa3 == ritr->first )
            {
                cout << ritr->second << " ";
            }
            if( mniejsza3 == ritr->first )
            {
                cout << ritr->second << " ";
            }
        }
        if(( liczba >= 1000 ) &&( liczba <= 1000000 ) &&( liczba != ritr->first ) )
        {
            mniejsza =( liczba / 1000 );
            nowa = liczba - mniejsza;
           
            /*if(nowa == ritr -> first)
                        {
                            cout << ritr -> second << " ";
                        }*/
            if( mniejsza == ritr->first )
            {
                cout << ritr->second << " " << "tys.";
            }
        }
    }
    return 0;
}

P-176247
mizie
Propozycja
» 2020-02-18 10:19:26
Mam nadzieję, że poniższy kod przyda ci się w szukaniu własnego rozwiązania. Zaznaczam, że moja jest tylko implementacja z wykorzystaniem mapy, o którą pytasz. Źródło pomysłu na algorytm (opartego na tablicach) podane jest w komentarzu na początku kodu.

C/C++
// zamiana liczby na zapis slowny z wykorzystaniem mapy, pomysl algorytmu zaczerpniety od Tomasz Lubinski (c)2019, www.algorytm.org
#include <iostream>
#include <string>
#include <map>
#include <random>
using std::string;
using std::cout;
using std::cin;
using std::endl;

const std::map < short, string > liczby_slownie = {
    { 0, "" }, { 1, " jeden" }, { 2, " dwa" }, { 3, " trzy" }, { 4, " cztery" }, { 5, " piec" },
    { 6, " szesc" }, { 7, " siedem" }, { 8, " osiem" }, { 9, " dziewiec" }, { 10, " dziesiec" },
    { 11, " jedenascie" }, { 12, " dwanascie" }, { 13, " trzynascie" }, { 14, " czternascie" }, { 15, " pietnascie" },
    { 16, " szesnascie" }, { 17, " siedemnascie" }, { 18, " osiemnascie" }, { 19, " dziewietnascie" },
    { 20, " dwadziescia" }, { 30, " trzydziesci" }, { 40, " czterdziesci" }, { 50, " piecdziesiat" },
    { 60, " szescdziesiat" }, { 70, " siedemdziesiat" }, { 80, " osiemdziesiat" }, { 90, " dziewiecdziesiat" },
    { 100, " sto" }, { 200, " dwiescie" }, { 300, " trzysta" }, { 400, " czterysta" }, { 500, " piecset" },
    { 600, " szescset" }, { 700, " siedemset" }, { 800, " osiemset" }, { 900, " dziewiecset" }
};
const string magnitude[ 5 ] = { "", " tys.", " mln.", " mld.", " bln." };

int main()
{
    cout << "Podaj ilosc liczb (od 1 do 1000), ktore chcesz zapisac slownie: ";
    int i { 0 };
    if( !( cin >> i ) || i < 1 || i > 1000 ) {
        cout << "Bledne dane.\n";
        system( "PAUSE" );
        return 1;
    }
   
    std::random_device rd;
    std::default_random_engine dre( rd() );
    std::uniform_int_distribution < long long > dist( 1, 1000000000000 ); // przedzial losowanych liczb testowych
   
    while( i > 0 ) {
        long long x { 0 }, temp { 0 };
        x = dist( dre );
        temp = x;
        string slownie = "";
        int itm { 0 }, j { 0 }, koncowka { 0 };
        if( x == 0 ) slownie = "zero";
       
        while( x > 0 ) {
            koncowka = x % 10;
            x /= 10;
            if(( j == 0 ) &&( x % 100 != 0 || koncowka != 0 ) )
                 slownie.insert( 0, magnitude[ itm ] );
           
            if(( j == 0 ) &&( x % 10 != 1 ) )
                 slownie.insert( 0, liczby_slownie.find( koncowka )->second );
           
            if(( j == 0 ) &&( x % 10 == 1 ) ) {
                slownie.insert( 0, liczby_slownie.find( koncowka + 10 )->second );
                x /= 10;
                j += 2;
                continue;
            }
            if( j == 1 )
                 slownie.insert( 0, liczby_slownie.find( koncowka * 10 )->second );
           
            if( j == 2 ) {
                slownie.insert( 0, liczby_slownie.find( koncowka * 100 )->second );
                j = - 1;
                if( itm < 5 )
                     ++itm;
               
            }
            ++j;
        }
        std::cout << temp << " to: " << slownie << "\n";
        --i;
    }
    system( "PAUSE" );
    return 0;
}
P-176252
Biedrzyk
Temat założony przez niniejszego użytkownika
» 2020-02-18 13:43:13
Dzięki za podpowiedź, będę kombinował.
P-176254
Biedrzyk
Temat założony przez niniejszego użytkownika
» 2020-02-23 13:28:47
Dopiero po kilku dniach znów mogłem zasiąść do zadania i na razie doszedłem do tego:

C/C++
#include <iostream>
#include <string>
#include <map>

using namespace std;

int main()
{
    map < int, string >::reverse_iterator ritr;
    map < int, string > inWords;
    inWords[ 1 ] = "jeden";
    inWords[ 2 ] = "dwa";
    inWords[ 3 ] = "trzy";
    inWords[ 4 ] = "cztery";
    inWords[ 5 ] = "piec";
    inWords[ 6 ] = "szesc";
    inWords[ 7 ] = "siedem";
    inWords[ 8 ] = "osiem";
    inWords[ 9 ] = "dziewiec";
    inWords[ 10 ] = "dziesiec";
    inWords[ 11 ] = "jedenascie";
    inWords[ 12 ] = "dwanascie";
    inWords[ 13 ] = "trzynascie";
    inWords[ 14 ] = "czternascie";
    inWords[ 15 ] = "pietnascie";
    inWords[ 16 ] = "szesnascie";
    inWords[ 17 ] = "siedemnascie";
    inWords[ 18 ] = "osiemnascie";
    inWords[ 19 ] = "dziewietnascie";
    inWords[ 20 ] = "dwadziescia";
    inWords[ 30 ] = "trzydziesci";
    inWords[ 40 ] = "czterdziesci";
    inWords[ 50 ] = "piecdziesiat";
    inWords[ 60 ] = "szczescdziesiat";
    inWords[ 70 ] = "siedemdziesiat";
    inWords[ 80 ] = "osiemdziesiat";
    inWords[ 90 ] = "dziewiecdziesiat";
    inWords[ 100 ] = "sto";
    inWords[ 200 ] = "dwiescie";
    inWords[ 300 ] = "trzysta";
    inWords[ 400 ] = "czterysta";
    inWords[ 500 ] = "piecset";
    inWords[ 600 ] = "szescset";
    inWords[ 700 ] = "siedemset";
    inWords[ 800 ] = "osiemset";
    inWords[ 900 ] = "dziewiecset";
   
    int liczba = 0;
    int mnoznik = 10, wynik = 0;
    int * pomoc;
    pomoc = new int[ mnoznik ];
   
    cin >> liczba;
   
    for( map < int, string >::reverse_iterator ritr = inWords.rbegin(); ritr != inWords.rend(); ritr++ )
    {
        if( liczba == ritr->first )
        {
            cout << ritr->second;
        }
        if(( liczba > 20 ) &&( liczba != ritr->first ) )
        {
            do
            {
                wynik = liczba % mnoznik;
                liczba = liczba - wynik;
                mnoznik *= 10;
                for( map < int, string >::reverse_iterator ritr = inWords.rbegin(); ritr != inWords.rend(); ritr++ )
                {
                    if( wynik == ritr->first )
                    {
                        cout << ritr->second << " ";
                    }
                    if( liczba == ritr->first )
                    {
                        cout << ritr->second << " ";
                    }
                    if(( wynik >= 1000 ) &&( wynik < 1000000 ) )
                    {
                        wynik /= 1000;
                        cout << "tys.";
                    }
                    if(( wynik >= 1000000 ) &&( wynik < 1000000000 ) )
                    {
                        wynik /= 1000000;
                        cout << "mln.";
                    }
                    if(( wynik >= 1000000000 ) &&( wynik < 1000000000000 ) )
                    {
                        wynik /= 1000000000;
                        cout << "mld.";
                    }
                    if(( wynik >= 1000000000000 ) &&( wynik < 1000000000000000 ) )
                    {
                        wynik /= 1000000000000;
                        cout << "bln.";
                    }
                }
            }
            while(( wynik > 0 ) &&( liczba > 0 ) );
           
        }
        return 0;
    }
}

program gubi się przy liczbach pełnych tj. 12000000, odczytuje od tyłu liczbę( co rozumiem bo odcina kolejne liczby i musi porównać z mapą). Teraz najlepiej by było w pierwszej kolejności odwrócić kolejność odczytywanych liczb a potem zająć się odczytywaniem pełnych liczb - prosiłbym o podpowiedź.
P-176279
pekfos
» 2020-02-23 14:13:47
Ta mapa jest tu bardziej utrudnieniem niż pomocą. Napisz funkcję, która generuje zapis słowny liczby z zakresu [0; 1000). Do tego wystarczą 3 tablice na look-up słów dla cyfr na pozycjach setek, dziesiątek i jedności. Potem to już tylko "X milionów Y tysięcy Z".
Look-up ma zawsze charakter pomocniczy w konstrukcji algorytmu. Zaczynanie od mapy wartości jako od "łatwiejszej części" to budowanie piramidy zaczynając od góry. Sensowne tablice pomocnicze do tego zadania mają klucze z przedziału [0; 9] co jest zadaniem dla tablicy, nie mapy. Indeksowanie w tablicy znacznie szybsze od wyszukiwania w mapie, a Ty nawet nie używasz wyszukiwania, tylko jeszcze wolniejszego iterowania po niej.
P-176280
Biedrzyk
Temat założony przez niniejszego użytkownika
» 2020-02-23 19:42:29
Dzięki, spróbuję pójść w tym kierunku.
P-176282
Biedrzyk
Temat założony przez niniejszego użytkownika
» 2020-03-11 00:05:04
Kod mam już gotowy ale pojawił się mały problem - przekształca mi ładnie liczby na słowa, ale gdy przyszło do stworzenia pętli to niejako dopisuje mi kolejne wprowadzane stringi :/ wiem, że trzeba wyzerować stringa, ale próbowałem już z clear, ignore, sync, po prostu liczba = ""; ale nie dało to żadnego efektu np. wpisuję 2 dostaję dwa potem wpisuję 5 i dostaję pięć tys. dwa.
Wstawiam kod z pastebina https:pastebin.comvvwm0UqU
P-176344
nanoant20
» 2020-03-11 15:05:24
w linku który podałeś zabrakło "/" po .com D
czyść kontener vector w pętli
C/C++
for( int i = 0; i < iloscTestow; i++ )
{
    cin >> liczba;
    podajSlownyZapisLiczbyTrzycyfrowej( liczba, liczby );
    liczby.clear(); //nazwavector.clear() <-- dopisz
}
P-176345
« 1 » 2
  Strona 1 z 2 Następna strona