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

Najbliższy sąsiad - cykl hamiltona - opis/optymalizacja kodu

0 głosów
875 wizyt
pytanie zadane 4 listopada 2019 w C i C++ przez air855 Nowicjusz (220 p.)
otagowane ponownie 4 listopada 2019 przez air855

Witam serdecznie,
Około dwa tygodnie temu napisałem program, który w najbliższych dniach muszę oddać, mamy także wyjaśnić słownie co program robi. Dane mam pięć punktów, program ma przejść przez wszystkie punkty, obliczyć najkrótszą trasę oraz powrócić do wskazanego przez nas punktu startowego. Chciałbym zapytać o ewentualne sugestie - czy warto o czymś dodatkowo wspomnieć lub może zmienić, aby program był bardziej funkcjonalny? Opisy znajdują się w komentarzach. 

 

#include <iostream>
#include <math.h>
#include <iomanip>
using namespace std;

float dlugosc(int x1,int x2, int y1, int y2)
    float dlugosc;
    dlugosc=sqrt(pow(x2-x1,2)+pow(y2-y1,2)); //wzór, z którego będziemy korzystać
    return dlugosc;
}


int main()
{
    float suma_drogi=0,odleglosc_do_pierwszego=0; //wyzerowane zmienne, pomaga w uniknęciu błędów
    int sasiad;
    int x=0,y=0;
    int iloscpkt=5;
    int punkt_start=0;
    float wspolrzedne[100][100]; // tablica na 100 zankow[?]

cout<<"Domyslna ilosc punktow: 5, "<<"podaj wspolrzedne x i y tych punktow: "<<endl;

    for (int i=0,j=1;i<iloscpkt;i++,j++) //petla - wczytuje wspolrzedne punktow
    {
        cout<<"PUNKT "<<j<<" - "<<"wpolrzedna x"<< ": ";
        cin>>x;
        wspolrzedne[i][0]=x; //
        cout<<"PUNKT "<<j<<" - "<<"wpolrzedna y"<< ": ";
        cin>>y;
        wspolrzedne[i][1]=y;
    }

        cout << "\nPunkt startowy: ";
        cin>>punkt_start;

    punkt_start--; // dekrementacja, wartosci w tablicy zaczynają się od zera, wybierajac punkt startowy 4, chodzilo nam o pozycje 3 w tablicy.
    bool odwiedzone[iloscpkt];
    for(int i=0;i<iloscpkt;i++)
        odwiedzone[i]=false; //oznacza nam wszystkie miasta jako nieodwiedzone

    odwiedzone[punkt_start]=true; //potem pierwszy punkt oznacza jako odwiedzony i kazdy kolejny, ktory zostanie odwiedzony
    cout<<punkt_start+1; //miejsce w tablicy zaczyna sie od 0, stad dodajemy wartosc 1, bo chcemy wartość o 1 większą.
    int temp = punkt_start; //zmienna tymczasowa, coś jak schowek [(pytanie po co)]

    for(int i=0;i<iloscpkt-1;i++){
        int x1=wspolrzedne[temp][0]; //pobiera dane z tablicy, wspolrzedne x,y
        int y1=wspolrzedne[temp][1];
        float dystans=0, najblizsza_odleglosc=0;
        bool first = true; //oznacza miasto jako odwiedzone

        for(int i=0;i<iloscpkt;i++){
            cout<<setprecision(2); // precyzja - ilosc miejsc po przecinku
            if(odwiedzone[i]==false) // jezeli punkt jest nieodwiedzony to liczymy odleglosc
{
            dystans=dlugosc(x1,wspolrzedne[i][0],y1,wspolrzedne[i][1]);  //wstawia do wzoru z metody wsporzedne
            // cout<<"dyst: "<<dystans<<endl;
            if(first == true){ // jesli odwiedzono punkt to juz go nie liczy
                najblizsza_odleglosc = dystans+1; 
                first = false;
            }
            if(dystans != 0 && dystans < najblizsza_odleglosc) 
                {
                najblizsza_odleglosc = dystans;
                sasiad=i;
                }
            }
        }
        suma_drogi += najblizsza_odleglosc; //sumuje juz droge przebyta przez wszystkie pinkty
        temp = sasiad;
        odwiedzone[temp] = true;
        cout<<" -> "<<sasiad+1;
    }
    cout<<setprecision(2);
    cout<<" --> "<<punkt_start+1;
    odleglosc_do_pierwszego=dlugosc(wspolrzedne[punkt_start][0],wspolrzedne[sasiad][0],wspolrzedne[punkt_start][1],wspolrzedne[sasiad][1]); //odleglosc z ostatniego pkt do pkt 1 startowego
    cout<<"\nCalkowita dlugosc trasy: "<<odleglosc_do_pierwszego+suma_drogi;

return 0;
}

Wstawiam także przykład, na którym będę to przedstawiać - dla jasności.

1 odpowiedź

+1 głos
odpowiedź 4 listopada 2019 przez draghan VIP (106,230 p.)
wybrane 5 listopada 2019 przez air855
 
Najlepsza

(to się chyba nie powinno kompilować, brakuje co najmniej jednej klamry)

Nadaj trochę ładniejszej formy, żeby lepiej się Twój kod czytało: przejedź to jakimś automatem formatującym, żeby porobił ładne wcięcia i wyrównał klamerki. Popraw literówki. Postaraj się nie wykonywać kilku operacji w jednej linii (jak np. u Ciebie w linii 15.). Postaraj się trzymać jednej konwencji - nie mieszaj identyfikatorów polskich z angielskimi.

Zmienna `sasiad` jest niezainicjalizowana, co wygląda o tyle zabawnie że linijkę wyżej masz komentarz o tym, dlaczego inicjalizujesz zmienne.

Tablica `wspolrzedne` tak naprawdę zmieści 100*100 elementów, czyli 10000, a Ty tutaj używasz tylko dwóch pierwszych komórek drugiego wymiaru.

W forze wczytującym niepotrzebnie definiujesz drugą zmienną specjalnie dla wypisania o jeden większej liczby.

Poniższy kod jest nielegalny w C++, rozmiar tablicy na stosie musi być znany w czasie kompilacji:

int iloscpkt = 5;

// (...)

bool odwiedzone[iloscpkt];

...a to made my day:

int temp = punkt_start; //zmienna tymczasowa, coś jak schowek [(pytanie po co)]

:)

Generalnie mam wrażenie że nie jest potrzebne tworzenie tylu zmiennych do implementacji tego algorytmu, sprawia to wrażenie lekkiego chaosu.

komentarz 4 listopada 2019 przez air855 Nowicjusz (220 p.)
Bardzo dziękuję za powyższe rady, dostosuję się do nich. Przyznaję, że nie jestem dobry w programowaniu - wybrałem kierunek informatyka, jednak jestem na specjalizacji grafika, więc programowaniem nie interesuję się aż tak bardzo, ale trzeba znać chociaż podstawy ;)  Nie ukrywam, że napisanie tego zajęło mi naprawdę SPORO czasu. Cieszę się także, że zrobiłem komuś dzień swoimi zabawnymi, chociaż niezbyt mądrymi komentarzami :D

Zgadza się - jednej klamry nie było, problem naprawiony. Gdzieś przypadkiem mi uciekła przy usuwaniu komentarza.

Mam jeszcze kilka pytań:

1. Zmniejszyłem tablice 'wspolrzedne' i ma wymiary 10*10, czy tyle jest okej?

2. Czy w funkcji wczytującej for wczytanie definiowanie drugiej zmiennej jest błędem? Rzeczywiście, wystarczyło zamiast j, wpisać i+1 (i tak zrobiłem w poprawce), jednak chciałbym wiedzieć na przyszłość.

3. Mam wrażenie, że nie do końca rozumiem, dlaczego przez to kod jest "nielegalny", po dopisaniu klamry kod się kompiluje. A jęsli już mówimy o legalności to jak poprawnie zdefiniować tablicę w tym wypadku?

Bardzo jestem wdzięczny za porady, bardzo się gubię w pisaniu programów/algorytmów i naprawdę staram się uczyć na błędach. Jednak super jest to, że są osoby, które wskażą błędy, których nie jest się świadom :)
komentarz 5 listopada 2019 przez draghan VIP (106,230 p.)

Przyznaję, że nie jestem dobry w programowaniu - wybrałem kierunek informatyka, jednak jestem na specjalizacji grafika, więc programowaniem nie interesuję się aż tak bardzo, ale trzeba znać chociaż podstawy ;)  Nie ukrywam, że napisanie tego zajęło mi naprawdę SPORO czasu

Jak na początek kod wygląda przyzwoicie. :)

1. Zmniejszyłem tablice 'wspolrzedne' i ma wymiary 10*10, czy tyle jest okej?

A może zróbmy prosty eksperyment. Przeanalizuj, proszę, swój program i powiedz mi, ile "komórek pamięci" na owe współrzędne potrzebujesz. Możesz to zrobić całkowicie statycznie, patrząc na kod i rozpisując sobie kolejne iteracje pętli lub ułatwić to sobie przy pomocy debuggera.

2. Czy w funkcji wczytującej for wczytanie definiowanie drugiej zmiennej jest błędem? Rzeczywiście, wystarczyło zamiast j, wpisać i+1 (i tak zrobiłem w poprawce), jednak chciałbym wiedzieć na przyszłość.

Nie jest błędem, bo nie wprowadza to niestabilności w działaniu algorytmu i program wykonuje to co ma wykonać. Tylko po prostu rzuciło mi się to w oczy. Nie ma to większego znaczenia z punktu widzenia użyteczności ani wydajności. Jedyny plus wyeliminowania tej zmiennej to odrobinę schludniejszy kod, bo upraszczasz w ten sposób definicje w pętli for.

3. Mam wrażenie, że nie do końca rozumiem, dlaczego przez to kod jest "nielegalny", po dopisaniu klamry kod się kompiluje. A jęsli już mówimy o legalności to jak poprawnie zdefiniować tablicę w tym wypadku?

Język C++ jest standaryzowany przez ISO. Taka konstrukcja jest niezgodna z żadną wersją standardu C++. Pisząc taki kod nie masz gwarancji, że po jego skompilowaniu innym kompilatorem lub na innej platformie będzie on działał tak jak u Ciebie.
Zgodnie z formułkami, wyrażenie w środku nawiasów prostokątnych przy definicji tablicy, musi być stałe i znane w czasie kompilacji. Podanie tam zmiennej non-const powinno wygenerować przynajmniej ostrzeżenie kompilatora. Niektóre kompilatory wspierają taki feature na zasadzie rozszerzenia standardu - czyli kompilując taki kod takim kompilatorem wiesz, że będzie okej, natomiast świadomie wykraczasz poza standaryzowany C++ i zgadzasz się na to, że będzie to działać tylko w danym środowisku.

Jeśli chcesz zrobić to poprawnie, masz kilka opcji. Możesz na przykład nadać zmiennej 'iloscpkt' kwalifikator 'const' (lub 'constexpr'), co uczyni ją stałą i będziesz mógł legalnie użyć jej do utworzenia zwykłej tablicy na stosie:

const int iloscpkt = 5;

// lub:
// constexpr int iloscpkt = 5;
 
// (...)
 
bool odwiedzone[iloscpkt];

Albo użyć jakiegoś standardowego kontenera (np. std::vector), jeśli wiesz że np. będziesz chciał mieć możliwość zmiany rozmiaru tablicy podczas działania programu.

Bardzo jestem wdzięczny za porady, bardzo się gubię w pisaniu programów/algorytmów i naprawdę staram się uczyć na błędach.

Po prostu ćwicz, będzie tylko lepiej.

A jeśli chcesz jeszcze sobie poulepszać swój program, to przyjrzyj się warunkom brzegowym samego algorytmu (czy na pewno poprawnie obsługujesz specjalne przypadki danych wejściowych) oraz czy przypadkiem nie pozwalasz użytkownikowi na podanie nieprawidłowych danych.

Podobne pytania

0 głosów
1 odpowiedź 445 wizyt
pytanie zadane 25 maja 2015 w C i C++ przez Adam Knie Mądrala (5,650 p.)
0 głosów
1 odpowiedź 355 wizyt
0 głosów
1 odpowiedź 302 wizyt
pytanie zadane 21 stycznia 2022 w C i C++ przez BKantur Nowicjusz (160 p.)

93,605 zapytań

142,529 odpowiedzi

322,999 komentarzy

63,095 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

Kursy INF.02 i INF.03
...