Witam, mam problem z zadaniem Tetris 3D z XIII OI - http://main.edu.pl/pl/archive/oi/13/tet , próbowałem sam to zrobić przed przeczytaniem wzorowego rozwiązania z książeczki. Większość testów jest wykonywana bezbłędnie (w niektórych na mainie zwraca mi program wywłaszczony), ale są 3 testy w jakich mam zły wynik (testy: tet3d, tet4d, tet13b) - są to duże testy i sam sobie nie poradzę, algorytm według jakiego działa program moim zdaniem nie wydaje się być zły, ale zastanawia mnie dlaczego te wyniki są nie takie jak powinny.
Schemat programu wygląda następująco - tworzone jest drzewo na wskaźnikach, następnie dla każdego klocka wyszukiwany jest najwyższy punkt, który potem zwiększam o wysokość danego klocka, potem aktualizuję tą wysokość na całym obszarze na jaki spada klocek.
#include <cstdio>
using namespace std;
// x, y - początek wieżchołka
// d_x, d_y długości klocków
// wielk - wielkość jaką będziemy uzupełniać
short x, y, d_x, d_y;
int wielk;
// struktura drzewa
// ilosc - przechowuje jaka na danym węźle została zaktualiziwana wysokość
// ilosc_max - jaka wysokość jest masymalna w danym przedziale dla jakiego jest węzeł
// wskaźniki xy - prowadzą do przedziału dla pierwszej połowy z zakresu X i zakresy Y
// tam gdzie większa litera to przedział dla tej zmiennej będzie w większej połowie
// konstruktor odpowiednio zeruje zmienne na 0
struct ss {
int ilosc;
int ilosc_max;
ss *xy, *xY, *Xy, *XY;
ss() {
ilosc_max = 0;
ilosc = 0;
}
};
// zwraca większą liczbę
int max(int a, int b) {
if (a > b)
return a;
return b;
}
// uzupełnienie na dodawaniu rozgałęzień o mniejszym przedziale pól
void uzupelnij(ss *pocz, short pocz_x, short kon_x, short pocz_y, short kon_y) {
// tu się nie rozgalezia, bo pole elementarne 1x1
if (pocz_x == kon_x - 1 && pocz_y == kon_y - 1)
return;
else if (pocz_y == kon_y - 1) {
// jak rozgalezia sia na OX bo Y ma szer 1
int sr = (pocz_x + kon_x) / 2;
(*pocz).xy = new ss;
(*pocz).Xy = new ss;
uzupelnij((*pocz).xy, pocz_x, sr, pocz_y, kon_y);
uzupelnij((*pocz).Xy, sr, kon_x, pocz_y, kon_y);
}
else if (pocz_x == kon_x - 1) {
// jak rozgalezia sia na OY bo X ma szer 1
int sr = (pocz_y + kon_y) / 2;
(*pocz).xy = new ss();
(*pocz).xY = new ss();
uzupelnij((*pocz).xy, pocz_x, kon_x, pocz_y, sr);
uzupelnij((*pocz).xY, pocz_x, kon_x, sr, kon_y);
}
else {
// jak rozgalezia sią na OX i OY
int sr_y = (pocz_y + kon_y) / 2;
int sr_x = (pocz_x + kon_x) / 2;
(*pocz).xy = new ss;
(*pocz).Xy = new ss;
(*pocz).xY = new ss;
(*pocz).XY = new ss;
uzupelnij((*pocz).xy, pocz_x, sr_x, pocz_y, sr_y);
uzupelnij((*pocz).xY, pocz_x, sr_x, sr_y, kon_y);
uzupelnij((*pocz).Xy, sr_x, kon_x, pocz_y, sr_y);
uzupelnij((*pocz).XY, sr_x, kon_x, sr_y, kon_y);
}
}
// znalenienie maxa na danym przedziale polega na przeszukiwaniu
// tylko tych węzłów na których może znajdować się szukany fragment pola,
// na którym chcemy znaleźć maxa
// jak przedział cały zawiera się w polu to bierzemy ilosc_max - bo interesuje
// nas najwyższa wartość, natomiast jak tylko część to bieszemy ilosc,
// bo jeśli ta ilość jest najwyższa to nie znajdziemy jej w mniejszych przedziałach
int max_wysokosc(ss *el, short pocz_x, short kon_x, short pocz_y, short kon_y) {
// jak fragmencik się zawiera centralnie w przedziale szukanym
if (x <= pocz_x && kon_x <= x + d_x
&& y <= pocz_y && kon_y <= y + d_y)
return (*el).ilosc_max;
// jak szukamy odpowiednich orzedziałów
int sr_y = (pocz_y + kon_y) / 2;
int sr_x = (pocz_x + kon_x) / 2;
int max_wys = (*el).ilosc;
// jak pierwszy x i y
if (x < sr_x && y < sr_y)
max_wys = max(max_wys, max_wysokosc((*el).xy, pocz_x, sr_x, pocz_y, sr_y));
// jak drugi x i pierwszy y
if (pocz_x < kon_x - 1
&& sr_x < x + d_x
&& y < sr_y)
max_wys = max(max_wys, max_wysokosc((*el).Xy, sr_x, kon_x, pocz_y, sr_y));
// jak pierwszy x i drugi y
if (pocz_y < kon_y - 1
&& x < sr_x
&& sr_y < y + d_y)
max_wys = max(max_wys, max_wysokosc((*el).xY, pocz_x, sr_x, sr_y, kon_y));
// jak drugi x i y
if (pocz_y < kon_y - 1 && pocz_x < kon_x - 1
&& sr_x < x + d_x
&& sr_y < y + d_y)
max_wys = max(max_wys, max_wysokosc((*el).XY, sr_x, kon_x, sr_y, kon_y));
return max_wys;
}
// uzupełnienie obszaru daną wysokością polega na znaleznieniu (taką metodą jak we
// wcześniejszych funkcjach) obszaru który całkowicie podlega pod dany zakres na którym dodajemy
// na takim węźle uzupełniamy ilosc_max i ilosc bo obie te watrtści się zmienią
// na wyżaszch przesziałach dajemy w ilosc_max wyiększą wartość z pośród obecnej ilosci_max i wielkości jaką dodajemy
void uzupelnij_obszar_wielkoscia(ss *el, short pocz_x, short kon_x, short pocz_y, short kon_y) {
// jak fragmencik się zawiera centralnie w przedziale szukanym
if (x <= pocz_x && kon_x <= x + d_x
&& y <= pocz_y && kon_y <= y + d_y) {
(*el).ilosc = wielk;
(*el).ilosc_max = wielk;
return;
}
// ustalanie maksymalnej wielkości na weźle i obliczenie śr
(*el).ilosc_max = max(wielk, (*el).ilosc_max);
short sr_y = (pocz_y + kon_y) / 2;
short sr_x = (pocz_x + kon_x) / 2;
// jak pierwszy x i y
if (x < sr_x && y < sr_y)
uzupelnij_obszar_wielkoscia((*el).xy, pocz_x, sr_x, pocz_y, sr_y);
// jak drugi x i pierwszy y
if (pocz_x < kon_x - 1
&& sr_x < x + d_x
&& y < sr_y)
uzupelnij_obszar_wielkoscia((*el).Xy, sr_x, kon_x, pocz_y, sr_y);
// jak pierwszy x i drugi y
if (pocz_y < kon_y - 1
&& x < sr_x
&& sr_y < y + d_y)
uzupelnij_obszar_wielkoscia((*el).xY, pocz_x, sr_x, sr_y, kon_y);
// jak drugi x i y
if (pocz_y < kon_y - 1 && pocz_x < kon_x - 1
&& sr_x < x + d_x
&& sr_y < y + d_y)
uzupelnij_obszar_wielkoscia((*el).XY, sr_x, kon_x, sr_y, kon_y);
}
int main() {
// wczytanie wiersza z głównymi danymi
short X, Y, N;
scanf("%hd%hd%hd", &X, &Y, &N);
// utworzenie drzewa z korzeniem w pocz
ss *pocz = new ss();
uzupelnij(pocz, 0, X, 0, Y);
// obsługa dodań kolejnych klocków
int w; // wysokość klocka
for (int a = 0; a < N; a++) {
scanf("%hd%hd%d%hd%hd", &d_x, &d_y, &w, &x, &y);
wielk = max_wysokosc(pocz, 0, X, 0, Y) + w;
uzupelnij_obszar_wielkoscia(pocz, 0, X, 0, Y);
}
// wyświetlenie wyniku
printf("%d", (*pocz).ilosc_max);
return 0;
}
Jeżeli coś źle napisałem to przypadkowo, sam uczę się algorytmiki, C++ też i pewnie mój kod nie jest idealny, ale bardzo proszę o pomoc :)
- Tetris.cpp (5 KB) - ściągnięć: 196