Problem Komiwojażera

Problem Komiwojażera
MD
  • Rejestracja:prawie 2 lata
  • Ostatnio:około rok
  • Postów:10
0

Hej, mam pewne zadanie do wykonania i bardzo mało czasu.

Przy użyciu C# mam napisać program wytyczający trasę mając do wykorzystania pewien zbiór obiektów (miasto1, miasto2, odległość między nimi)

Widziałem już kilka przykładów i omówień z Javy i C/C++ ale potrzebował bym pomocy przy utworzeniu takiej małej aplikacji konsolowej gdzie podając dwa miasta program wybierze najkrótszą trasę i poda kolejne mijane miejscowości + ostateczną odległość

edytowany 1x, ostatnio: Riddle
S4
, mam pewne zadanie do wykonania i bardzo mało czasu. to się trzeba było nie opier... przez cały semestr.
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:dzień
  • Lokalizacja:Poznań
  • Postów:8759
1

Ale w ogóle rozumiesz, jak to ma działać? Jak działa algorytm?
Czy umiałbyś to zrobić na kartce, albo komuś wytłumaczyć kroki, jakie trzeba zrobić, żeby zadanie rozwiązać?
Na razie, poza opisem zadania, nie dałeś niczego. Także nie wiem, czy potrzebujesz pomocy (wtedy napisz konkretnie, gdzie utknąłeś), czy czekasz, aż ktoś to zrobi za Ciebie?


MD
  • Rejestracja:prawie 2 lata
  • Ostatnio:około rok
  • Postów:10
0

Aktualnie mam utworzoną klasę z trasami. Co do wiedzy, to wydaje mi się ;) że umiałbym rozrysować komuś na kartce takie zagadnienie.
Trochę spanikowałem bo będę robił bardziej zawansowany algorytm.

cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:dzień
  • Lokalizacja:Poznań
  • Postów:8759
1

Ewentualnie możesz skorzystać z Chat GPT. Zrobiłem to za Ciebie i oto odpowiedź :P


Witaj! Zadanie, które opisujesz, to problem najkrótszej ścieżki w grafie, który można rozwiązać za pomocą algorytmów takich jak Dijkstra, Bellmana-Forda lub A*. Oto kilka kroków, które pomogą Ci napisać program, który rozwiąże ten problem w C#:

  1. Zdefiniuj klasę Miasto, która będzie reprezentować każde miasto. Klasa powinna zawierać pola nazwa i sąsiedzi, które będą przechowywać informacje o nazwie miasta i o innych miastach, do których prowadzą bezpośrednie połączenia oraz ich odległości.
Kopiuj
public class Miasto
{
    public string Nazwa { get; set; }
    public Dictionary<Miasto, int> Sąsiedzi { get; set; }

    public Miasto(string nazwa)
    {
        Nazwa = nazwa;
        Sąsiedzi = new Dictionary<Miasto, int>();
    }
}
  1. Zdefiniuj klasę Graf, która będzie reprezentować zbiór miast i połączeń między nimi. Klasa powinna zawierać pole miasta, które będzie przechowywać informacje o wszystkich miastach w grafie.
Kopiuj
public class Graf
{
    public List<Miasto> Miasta { get; set; }

    public Graf()
    {
        Miasta = new List<Miasto>();
    }

    public void DodajMiasto(Miasto miasto)
    {
        Miasta.Add(miasto);
    }
}
  1. Dodaj metody do klasy Graf, które umożliwią dodanie połączeń między miastami. Metoda DodajPołączenie będzie dodawać połączenie między dwoma miastami o podanych nazwach i odległości.
Kopiuj
public void DodajPołączenie(string nazwaMiasta1, string nazwaMiasta2, int odległość)
{
    var miasto1 = Miasta.Find(m => m.Nazwa == nazwaMiasta1);
    var miasto2 = Miasta.Find(m => m.Nazwa == nazwaMiasta2);

    miasto1.Sąsiedzi.Add(miasto2, odległość);
    miasto2.Sąsiedzi.Add(miasto1, odległość);
}
  1. Napisz metodę NajkrótszaŚcieżka, która za pomocą algorytmu Dijkstry wyznaczy najkrótszą ścieżkę między dwoma miastami. Metoda powinna przyjmować nazwy miast jako argumenty oraz zwracać listę miast, które należy odwiedzić, aby dotrzeć z pierwszego miasta do drugiego, oraz długość tej trasy.
Kopiuj
public (List<Miasto> Ścieżka, int Długość) NajkrótszaŚcieżka(string nazwaMiasta1, string nazwaMiasta2)
{
    var start = Miasta.Find(m => m.Nazwa == nazwaMiasta1);
    var meta = Miasta.Find(m => m.Nazwa ==

MD
Fantastyczna sprawa z tym czatem, ale zastanawia mnie czy jest mozliwość wymusić na nim żeby dokończył swoje wypowiedzi. Bo tak jak w twoim przykładzie kod jest urwany.
cerrato
Wejdź sobie na czat, zadaj pytanie, a potem - jak dostaniesz niekompletną odpowiedź, to powiedz, że jest ona niekompletna i prosisz o całość :P Ja tak ostatnio miałem Flutterem - poprosiłem o przykład czegoś-tam, czat mi wypluł jedynie jakieś funkcje, które same się nie kompilowały. Poprosiłem o całość, którą mogę wkleić (z include, main() itp.) i taką dostałem.
MD
Mi odpowiada, że ma narzuconą długość odpowiedzi, ale z innej strony go zaszedłem, wkleiłem kod, który mi wypluł i poprosiłem, o implementacje takiego przykładu. Swoją drogą jest to przerażające..... Miły aspekt takiego AI , że jak poprosiłem o objaśnienie w krokach to faktycznie bardzo czytelnie zdefiniował problem i wytyczył kroki do jego rozwiązania.
cerrato
@MiltonD: tak, to jest i super i przerażające jednocześnie. I ważna uwaga - czasem AI popełnia błędy i pisze głupoty, także trzeba zawsze podchodzić do jego odpowiedzi ostrożnie.
MD
Tak, dlatego posłużyłem się nim bardziej jako poradnik, niż wykonawcę ;)
WE
  • Rejestracja:ponad 7 lat
  • Ostatnio:4 miesiące
  • Postów:72
0

Masz na zachętę:
https://dotnetfiddle.net/csInsp

Program rozwiązuje problem komiwojażera, ale bardzo niewydajnie. Sprawdza on po kolei wszystkie połączenia między punktem A a B i tak do czasu, aż znajdzie szukany punkt.

edytowany 2x, ostatnio: west
MD
  • Rejestracja:prawie 2 lata
  • Ostatnio:około rok
  • Postów:10
0

Wkleję efekt końcowy. Może się komuś przyda.
Wydaje się, że wyszło całkiem przyzwoicie.

Kopiuj
using Komiwojażer;
using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    static void Main(string[] args)
    {
        Graf graf = new Graf();
        odleglosci trasy = new odleglosci();

        // utwórz obiekt Miasto i dodaj go do klasy Graf wszystkie połączenia(sąsiadów). 
        foreach (var trasa in trasy.GetTrasy())
        {
            Miasto miasto1 = new Miasto(trasa.miejscowosc1);
            Miasto miasto2 = new Miasto(trasa.miejscowosc2);

            if (!graf.Miasta.Contains(miasto1))
                graf.DodajMiasto(miasto1);
            else
                miasto1 = graf.Miasta.Find(m => m.Nazwa == trasa.miejscowosc1);

            if (!graf.Miasta.Contains(miasto2))
                graf.DodajMiasto(miasto2);
            else
                miasto2 = graf.Miasta.Find(m => m.Nazwa == trasa.miejscowosc2);

            graf.DodajPołączenie(trasa.miejscowosc1, trasa.miejscowosc2, (double)trasa.odleglosc);
        }

        // znajdź najkrótszą trasę pomiędzy dwoma miastami. 

        //toDo
        //dla użytkownika należy wyświetlić wszystkie miasta i ma mieć możliwość wybrania najkrótszej
        var (ścieżka, długość) = graf.NajkrótszaŚcieżka("Miasto1", "Miasto2");

        // podaj resultat
        Console.WriteLine("Najkrótsza ścieżka:");
        int i = 1;
        foreach (var miasto in ścieżka)
        {
            if (i != ścieżka.Count())
            {
                i++;
                miasto.Nazwa += " -> ";
            }
            Console.Write(miasto.Nazwa);
        }
        Console.WriteLine($"\nRAZEM: {długość}");
    }

}
public class Miasto : IComparable<Miasto>
{
    public string Nazwa { get; set; }
    public Dictionary<Miasto, double> Sąsiedzi { get; set; }

    public Miasto(string nazwa)
    {
        Nazwa = nazwa;
        Sąsiedzi = new Dictionary<Miasto, double>();
    }

    //nieuzywany fragment ale wymaga tego zaimplementowany interfejs
    public int CompareTo(Miasto other)
    {
        return Nazwa.CompareTo(other.Nazwa);
    }
}

public class Graf
{
    public List<Miasto> Miasta { get; set; }

    public Graf()
    {
        Miasta = new List<Miasto>();
    }

    public void DodajMiasto(Miasto miasto)
    {
        Miasta.Add(miasto);
    }

    public void DodajPołączenie(string nazwaMiasta1, string nazwaMiasta2, double odległość)
    {
        var miasto1 = Miasta.Find(m => m.Nazwa == nazwaMiasta1);
        var miasto2 = Miasta.Find(m => m.Nazwa == nazwaMiasta2);

        miasto1.Sąsiedzi.Add(miasto2, odległość);
        miasto2.Sąsiedzi.Add(miasto1, odległość);
    }

    public (List<Miasto> Ścieżka, double Długość) NajkrótszaŚcieżka(string nazwaMiasta1, string nazwaMiasta2)
    {
        //określenie miejsca startu i końca trasy
        var start = Miasta.Find(m => m.Nazwa == nazwaMiasta1);
        var meta = Miasta.Find(m => m.Nazwa == nazwaMiasta2);

        var odległości = new SortedDictionary<Miasto, double>(Comparer<Miasto>.Create((x, y) => x.Nazwa.CompareTo(y.Nazwa)));
        var poprzednicy = new Dictionary<Miasto, Miasto>();
        var kolejka = new SortedSet<(double, Miasto)>();

        foreach (var _miasto in Miasta)
        {
            odległości[_miasto] = double.PositiveInfinity;
        }

        odległości[start] = 0;
        kolejka.Add((0, start));

        while (kolejka.Count > 0)
        {
            var (obecnaOdległość, obecneMiasto) = kolejka.Min;
            kolejka.Remove((obecnaOdległość, obecneMiasto));

            if (obecneMiasto == meta)
            {
                break;
            }

            foreach (var (sąsiad, odległość) in obecneMiasto.Sąsiedzi)
            {
                var alternatywnaOdległość = odległości[obecneMiasto] + odległość;
                if (alternatywnaOdległość < odległości[sąsiad])
                {
                    odległości[sąsiad] = alternatywnaOdległość;
                    poprzednicy[sąsiad] = obecneMiasto;
                    kolejka.Add((alternatywnaOdległość, sąsiad));
                }
            }
        }

        var ścieżka = new List<Miasto>();
        var miasto = meta;
        while (miasto != start)
        {
            ścieżka.Add(miasto);
            miasto = poprzednicy[miasto];
        }
        ścieżka.Add(start);
        ścieżka.Reverse();

        return (ścieżka, odległości[meta]);
    }

}



P.s.
Polskie nazwy w kodzie i komentarze są celowe. (choć wiem, że tak nie robi się, ale na potrzeby instruktarzowe chciałem to tak przedstawić.)

stivens
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 7 godzin
0
cerrato napisał(a):

Ewentualnie możesz skorzystać z Chat GPT. Zrobiłem to za Ciebie i oto odpowiedź :P


Witaj! Zadanie, które opisujesz, to problem najkrótszej ścieżki w grafie, który można rozwiązać za pomocą algorytmów takich jak Dijkstra, Bellmana-Forda lub A*. Oto kilka kroków, które pomogą Ci napisać program, który rozwiąże ten problem w C#:

Przeciez ten problem polega na znalezieniu cyklu Hamiltona. I ogolnie to jest NP. Co on bredzi o jakichs Djikstrach czy A*? :P


EDIT:

ale potrzebował bym pomocy przy utworzeniu takiej małej aplikacji konsolowej gdzie podając dwa miasta program wybierze najkrótszą trasę i poda kolejne mijane miejscowości + ostateczną odległość

Dobra. To jednak OP zle opisal (w temacie) co potrzebuje. Heh. :D


λλλ
edytowany 4x, ostatnio: stivens
GZ
  • Rejestracja:około 4 lata
  • Ostatnio:około rok
  • Postów:35
1

Autor prawdopodobnie nadal nie wie jak rozwiązać problem (bez urazy) ale go rozwiązał :)
Co jest bardziej potrzebne w życiu / pracy, umiejętność rozwiązania tego problemu czy dostarczenie rozwiązania ? Ja po kilku latach pracy mogę odpowiedzieć za siebie że to drugie.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)