Problem Komiwojażera

Problem Komiwojażera
MD
  • Rejestracja:prawie 2 lata
  • Ostatnio:ponad 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:około godziny
  • Lokalizacja:Poznań
  • Postów:8802
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:ponad 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:około godziny
  • Lokalizacja:Poznań
  • Postów:8802
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:17 dni
  • 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:ponad 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 2 godziny
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.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.