• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Drzewo Sterna-Brocota - szkopuł

Object Storage Arubacloud
+1 głos
462 wizyt
pytanie zadane 24 czerwca 2023 w C i C++ przez Szyszka Gaduła (3,490 p.)

Witam.

Chciałem rozwiązać zadanie: https://szkopul.edu.pl/problemset/problem/zFA7joqxZZ9lbwA0FoqjmZwP/site/?key=submissions

I to jest mój kod:

#include <iostream>
#include <vector>
#include <string>

std::pair<uint32_t, uint32_t> read_fraction(const std::string& fraction) {
	uint32_t i = 0;
	uint32_t nominator = 0;
	while (fraction[i] != '/') {
		nominator = nominator * 10 + (fraction[i] - '0');
		i++;
	}

	// Omit the '/'
	i++;

	uint32_t denominator = 0;
	while (i < fraction.size()) {
		denominator = denominator * 10 + (fraction[i] - '0');
		i++;
	}

	return std::make_pair(nominator, denominator);
}

int main()
{
	uint32_t n;
	std::cin >> n;

	std::vector<std::string> level{"0/1", "1/0"};
	std::vector<std::string> next_level(3);
	for (uint32_t i = 0; i < n; i++) {
		uint32_t added = 0;
		for (uint32_t j = 0; j < level.size() - 1; j++) {
			next_level[j + added] = level[j];

			std::pair<uint32_t, uint32_t> left = read_fraction(level[j]);
			std::pair<uint32_t, uint32_t> right = read_fraction(level[j + 1]);

			std::string result = std::to_string(left.first + right.first) + "/" + std::to_string(left.second + right.second);
			next_level[j + added + 1] = result;
			added++;
		}

		next_level[level.size() - 1 + added] = level[level.size() - 1];
		level = next_level;
		next_level.erase(next_level.begin(), next_level.end());
		next_level.resize(level.size() * 2 - 1);
	}

	for (const std::string& fraction : level)
		std::cout << fraction << " ";

	return 0;
}

Ale niestety nie mogę zaliczyć ostatniego testu, bo zużywam zbyt dużo pamięci. Właściwie zauważyłem że wystarczy około 5s i już zużywam 400mb. Przechowuję tylko ostatni level i kolejny, żeby właśnie tej pamięci oszczędzić. Co tu mogę jeszcze poprawić, żeby zaliczyć na 100?

W tagach zadania wskazane jest użycie rekurencji - ale czy to tylko nie pogorszy problemu z pamięcią? Poza tym takie rozwiązanie wydaje mi się trudniejsze

komentarz 25 czerwca 2023 przez Szyszka Gaduła (3,490 p.)
Jakąś wizję już mam, ale po 1. nie mam kompletnie pomysłu na przypadek podstawowy, a po 2. w którym momencie mogę wypisać ułamek? https://pastebin.com/R4dGGBnp

Jeśli w ogóle będę w którymś momencie wypisywał któryś ułamek - to zawsze będą duplikaty (jeśli dobrze myślę). A czy w ogóle podejście jest dobre? Najpierw liczę wszystkie ułamki dla lewego i potem wszystkie dla lewego i tego nowo powstałego, a potem tak samo dla prawego.
komentarz 25 czerwca 2023 przez Whistleroosh Maniak (56,980 p.)
1. Spójrz na liczbe n i co ona oznacza

2. Podejście jest dobre. Spójrz na kod który wysłałem wczesniej on dokładnie rozwiązuje ten problem
komentarz 25 czerwca 2023 przez Szyszka Gaduła (3,490 p.)
Ok, mam takie coś: https://pastebin.com/Ki3Sr1nX

Oczywiście nie działa. Mój max który konstruuje w main mówi ile elementów musi się znaleźć w ostatnim levelu drzewa.

Rozumiem, że po 1 jest problem z synchronizacją tego count (ta gałąź która pójdzie na lewo i na prawo się nie dogadują, jakby liczone jest dwa razy więcej niż potrzeba jeśli dobrze myślę). Ale jest też jakiś inny problem, bo nawet jak zrobiłem count jako zmienną globalną to i tak źle działało.
komentarz 25 czerwca 2023 przez Whistleroosh Maniak (56,980 p.)
Jest dobrze tylko max jest za duży. To nie powinna być liczba elementów na levelu
komentarz 25 czerwca 2023 przez Szyszka Gaduła (3,490 p.)
Aha. Zrobiłem max jako n i działa. Jeszcze nie kumam czemu ale jak rozrysuje to może się dowiem.

2 odpowiedzi

+1 głos
odpowiedź 28 czerwca 2023 przez Eriss69 Gaduła (4,470 p.)
#include <iostream>
#include <vector>
#include <string>
 
std::pair<uint32_t, uint32_t> read_fraction(const std::string& fraction) {
    uint32_t i = 0;
    uint32_t nominator = 0;
    while (fraction[i] != '/') {
        nominator = nominator * 10 + (fraction[i] - '0');
        i++;
    }
 
    // Omit the '/'
    i++;
 
    uint32_t denominator = 0;
    while (i < fraction.size()) {
        denominator = denominator * 10 + (fraction[i] - '0');
        i++;
    }
 
    return std::make_pair(nominator, denominator);
}
 
int main()
{
    uint32_t n;
    std::cin >> n;
 
    std::vector<std::string> level{"0/1", "1/0"};
 
    for (uint32_t i = 0; i < n; i++) {
        std::vector<std::string> next_level(level.size() * 2 - 1);
        uint32_t added = 0;
 
        for (uint32_t j = 0; j < level.size() - 1; j++) {
            next_level[j + added] = level[j];
 
            std::pair<uint32_t, uint32_t> left = read_fraction(level[j]);
            std::pair<uint32_t, uint32_t> right = read_fraction(level[j + 1]);
 
            std::string result = std::to_string(left.first + right.first) + "/" + std::to_string(left.second + right.second);
            next_level[j + added + 1] = result;
            added++;
        }
 
        next_level[level.size() - 1 + added] = level[level.size() - 1];
        level = std::move(next_level);
    }
 
    for (const std::string& fraction : level)
        std::cout << fraction << " ";
 
    return 0;
}
  1. Zamiast tworzyć kopię wektora next_level, użyłem semantyki przenoszenia (std::move) do przeniesienia zawartości next_level do level. Działa to szybciej i zużywa mniej pamięci.

    pozdrawiam

0 głosów
odpowiedź 24 czerwca 2023 przez adrian17 Ekspert (344,860 p.)
Hmm, czemu w vectorach przechowujesz stringi, po czym z powrotem rozpakowujesz je do pary?

Na intuicję, przechowywanie par w vectorach i wyrzucenie stringów powinno poprawić zużycie pamięci (i czas) dobrych kilka razy.
komentarz 24 czerwca 2023 przez Szyszka Gaduła (3,490 p.)
Nie wiem czemu, chyba zamknąłem się w jakiejś dziwnej bańce podczas pisania xD. Czas jest sporo krótszy, zużycie pamięci też, ale to wciąż za mało dla ostatniego testu. Tak to wygląda obecnie: https://pastebin.com/gvHrbm1a

Podobne pytania

+1 głos
1 odpowiedź 177 wizyt
pytanie zadane 7 czerwca 2023 w C i C++ przez Szyszka Gaduła (3,490 p.)
0 głosów
1 odpowiedź 195 wizyt
pytanie zadane 30 maja 2023 w C i C++ przez Szyszka Gaduła (3,490 p.)
0 głosów
1 odpowiedź 305 wizyt
pytanie zadane 28 maja 2023 w C i C++ przez Szyszka Gaduła (3,490 p.)

92,579 zapytań

141,429 odpowiedzi

319,657 komentarzy

61,963 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...