Zadanie JLITOSL ze SPOJ'a - drobny problem z kodem // C++

0

Cześć. Napisałem rozwiązanie zadania ze SPOJ'a: https://pl.spoj.com/problems/JLITOSL/ . Kod działa poprawnie dla liczb, które skladaja sie z trzycyfrowych segmentów cyfr od 1 do 9. W przypadku pojawienia się w rozpatrywanej liczbie zera lub gdy ilość cyfr w rozpatrywanej liczbie nie jest podzielna przez 3, pojawiają się dodatkowe spacje (liczba 013 jest przekształcana na "_trzynascie"). Byłbym wdzięczny za wskazówki, jak pozbyć się tych dodatkowych spacji z outputu mojego kodu...

http://ideone.com/m7IcHP

#include <iostream>
#include <map>
#include <vector>
#include <string>
 
using namespace std;
 
string zamienNaSlowo (int liczba)
{
    map <int, string> zapisSlowny;
    zapisSlowny [1] = "jeden";
    zapisSlowny [2] = "dwa";
    zapisSlowny [3] = "trzy";
    zapisSlowny [4] = "cztery";
    zapisSlowny [5] = "piec";
    zapisSlowny [6] = "szesc";
    zapisSlowny [7] = "siedem";
    zapisSlowny [8] = "osiem";
    zapisSlowny [9] = "dziewiec";
    zapisSlowny [10] = "dziesiec";
    zapisSlowny [11] = "jedenascie";
    zapisSlowny [12] = "dwanascie";
    zapisSlowny [13] = "trzynascie";
    zapisSlowny [14] = "czternascie";
    zapisSlowny [15] = "pietnascie";
    zapisSlowny [16] = "szesnascie";
    zapisSlowny [17] = "siedemnascie";
    zapisSlowny [18] = "osiemnascie";
    zapisSlowny [19] = "dziewietnascie";
    zapisSlowny [20] = "dwadziescia";
    zapisSlowny [30] = "trzydziesci";
    zapisSlowny [40] = "czterdziesci";
    zapisSlowny [50] = "piecdziesiat";
    zapisSlowny [60] = "szescdziesiat";
    zapisSlowny [70] = "siedemdziesiat";
    zapisSlowny [80] = "osiemdziesiat";
    zapisSlowny [90] = "dziewiecdziesiat";
    zapisSlowny [100] = "sto";
    zapisSlowny [200] = "dwiescie";
    zapisSlowny [300] = "trzysta";
    zapisSlowny [400] = "czterysta";
    zapisSlowny [500] = "piecset";
    zapisSlowny [600] = "szescset";
    zapisSlowny [700] = "siedemset";
    zapisSlowny [800] = "osiemset";
    zapisSlowny [900] = "dziewiecset";
 
    string slowo;
    map <int,string>::iterator it = zapisSlowny.find(liczba);
 
    if (it != zapisSlowny.end())
    {
        slowo = it->second;
    }
    return slowo;
}
 
void zamienLiczbeTrzycyfrowaNaSlowo(int liczbaTrzycyfrowa)
{
    int tymczasowa1, tymczasowa2 = 0;
    tymczasowa1 = liczbaTrzycyfrowa % 100;
    tymczasowa2 = liczbaTrzycyfrowa % 10;
    liczbaTrzycyfrowa = liczbaTrzycyfrowa - tymczasowa1;
 
    if (zamienNaSlowo(liczbaTrzycyfrowa) != " ")
        cout << zamienNaSlowo(liczbaTrzycyfrowa) << " ";
 
    if (tymczasowa1 < 20)
        cout << zamienNaSlowo(tymczasowa1);
    else
    {
        tymczasowa2 = tymczasowa1 % 10;
        tymczasowa1 = tymczasowa1 - tymczasowa2;
 
        if (zamienNaSlowo(tymczasowa1) != " ")
            cout << zamienNaSlowo(tymczasowa1) << " ";
 
        cout << zamienNaSlowo(tymczasowa2);
    }
}
 
vector <string> podzielStringNaCiagiTrzycyfrowe (string &liczba)
{
    const int dlugoscPodciagu = 3;
    int dlugoscLiczby = liczba.length();
    int liczbaPodciagow = dlugoscLiczby / dlugoscPodciagu;
 
    vector <string> wektorCiagowTrzycyfrowych;
 
    for (int i=liczbaPodciagow-1; i>=0; i--)
    {
        wektorCiagowTrzycyfrowych.push_back(liczba.substr(i*dlugoscPodciagu + dlugoscLiczby%dlugoscPodciagu, dlugoscPodciagu));
    }
 
    if (dlugoscLiczby % dlugoscPodciagu != 0)
        wektorCiagowTrzycyfrowych.push_back(liczba.substr(0,dlugoscLiczby%dlugoscPodciagu));
 
    return wektorCiagowTrzycyfrowych;
}
 
vector <int> zamienCiagiZnakowNaLiczby (vector<string> &wektorCiagowTrzycyfrowych)
{
    vector <int> wektorLiczbTrzycyfrowych;
    int dlugoscWektora = wektorCiagowTrzycyfrowych.size();
 
    for (int i=0; i<dlugoscWektora; i++)
        wektorLiczbTrzycyfrowych.push_back(stoi(wektorCiagowTrzycyfrowych [i]));
 
    return wektorLiczbTrzycyfrowych;
}
 
void zamienWektorNaZapisSlowny (vector <int> &wektorLiczbTrzycyfrowych)
{
    int dlugoscWektora = wektorLiczbTrzycyfrowych.size();
    string rzadWielkosci [5] = {" ","tys. ","mln. ","mld. ","bln. "};
 
    for (int i=dlugoscWektora-1; i>=0; i--)
    {
        zamienLiczbeTrzycyfrowaNaSlowo (wektorLiczbTrzycyfrowych[i]);
        cout << " " << rzadWielkosci [i];
    }
    cout << endl;
}
 
int main()
{
    int liczbaTestow;
    string liczba;
 
    cin >> liczbaTestow;
 
    for (int i=0; i<liczbaTestow; i++)
    {
        cin >> liczba;
 
        vector <string> wektorCiagowTrzycyfrowych = podzielStringNaCiagiTrzycyfrowe(liczba);
        vector <int> wektorLiczbTrzycyfrowych = zamienCiagiZnakowNaLiczby(wektorCiagowTrzycyfrowych);
        zamienWektorNaZapisSlowny (wektorLiczbTrzycyfrowych);
    }
    return 0;
}
0

Ja bym to zrobił inaczej, nie dzielił liczby na segmenty trzycyfrowe, tylko odcinał od końca po trzy cyfry (modulo 1000), przekształcał taką liczbę i pushował string do listy (żeby nie trzeba było odwracać), na koniec wydrukował listę po linijce.

0
lion137 napisał(a):

Ja bym to zrobił inaczej, nie dzielił liczby na segmenty trzycyfrowe, tylko odcinał(czyli odejmował tą resztę), od końca po trzy cyfry (modulo 1000), przekształcał taką liczbę i pushował string do listy (żeby nie trzeba było odwracać), na koniec wydrukował listę po linijce.

Dzięki, tylko czy to rozwiąże mój problem? Wydaje mi się, że istota całego problemu leży w funkcji przekształcającej trzycyfrowe ciągi, niezależnie od tego w jaki sposób zostały pozyskane z wyjściowego stringa? Upewniłem się, że mój kod poprawnie wyodrębnia segmenty, tj liczbę np. 12120012 dzieli na 12, 120 oraz 012. Tylko teraz jak zamienić to 012 na "dwanaście" a nie na " dwanascie" (z dodatkową spacją z przodu)

0

Na początek: nie odejmował (wtedy jest błąd), tylko ręcznie odcinał po trzy cyfry, zedytowałem post. A właśnie tak jak napisałem; liczba 12120012 będzie przetwarzana: 12, 120, 12. W każdym kroku: modulo 1000 i oderwanie trzech cyfr.

0

Tzn. ja zrozumiałem, co miałeś na myśli za pierwszym razem - że modulo ładnie wydzieli mi poszczególne liczby bez zera wiodącego. Z tym się zgadzam jak najbardziej i jest to fajny sposób, który wykorzystam na etapie optymalizacji, gdyby były problemy z przekroczeniem czasu. Tylko wciąz potrzebna jest funkcja przekształcająca liczby max trzycyfrowe na ich zapis slowny, a w mojej funkcji jest błąd, którego póki co nie mogę się pozbyć.

Mój program przekształca wszystkie liczby od 1 do 99 dodając tę nieszczęsną spację z przodu. Jeśli na inpucie programu wprowadzę np. "12", program w obecnej postaci przekształca mi to nie na "dwanaście" tylko na "_dwanaście". Taka sama sytuacja pojawia sie, gdy wprowadzę liczbę "012" - output to "_dwanascie". Podobnie "1" oraz "001" obie zwracają "_jeden". Ale gdy wprowadzam jakąkolwiek liczbę od 100 do 999, program zamienia ją jak należy.

Tu tkwi istota mojego problemu - poszukuję sposobu poprawienia funkcji przekształcającej liczby max 3-cyfrowe na słowa w przypadku, gdy te liczby składają się z jednej lub dwóch cyfr (albo mają z przodu jedno lub dwa zera).

2

Acha, ale przecież, już praktycznie, Masz rozwiązanie, Stablicowałeś od 0 do 20 i "pełne dziesiątki"; to teraz nie Dodawaj tego "underscore", tylko inne dwucyfrowe Zamieniaj bezpośrednio (x to liczba): jak nie jest w słowniku, to: lewa cyfra (x / 10), jak 2 to "dwadzieścia", i tak dalej i prawa cyfra (x mod 10) to "jeden", "dwa", ... Oczywiście, "krańcowy" przypader zera Masz załatwiony (string pusty, tak mi się wydaje wynika z opisu zadania).

0

Zrobiłem takiego facepalma, że aż mi czerwony ślad został na pysku... ;p Oczywiście masz racje, rozwiązanie jest dużo prostsze niz mi się wydawało. Chyba zmęczenie tematem dało mi się już we znaki i wywołało takiego brain farta... Dzięki śliczne za podpowiedż!

3

Offtopic:
Ta mapa jest niezbyt dobrze zdefiniowana. Zkładając, że masz C++11 lepiej było by tak:

string zamienNaSlowo(int liczba)
{
    static const map <int, string> zapisSlowny {
        { 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" },
    };

    string slowo;
    auto it = zapisSlowny.find(liczba);

    if (it != zapisSlowny.end())
    {
        slowo = it->second;
    }
    return slowo;
}

http://ideone.com/A0B9OE

Należy wyraźnie pochwalić bardzo dobrze zadane pytanie (nie wiem co poprawił kq, ale za pewne to było tylko drobne niedociągnięcie).

0

Dzięki za wskazówkę, będę o tym pamiętał przy kolejnym programie z mapą!

1 użytkowników online, w tym zalogowanych: 0, gości: 1