Имя пользователя:
Пароль:
 

Название темы: Задача на графы
Показать сообщение отдельно

Пользователь


Сообщения: 107
Благодарности: 9

Профиль | Цитировать


Вот алгоритм дейкстры на C#, вроде работал, давно писал. Может пригодится. Насколько я помню, он позволяет найти наиболее "лёгкий" путь между узлами графа (в графе каждое ребро имеет свой "вес").


Код: Выделить весь код
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace algorithmDijkstra
{
    public class Peak : IComparable<Peak>   // вершина
    {
        public int Number { get; set; } // номер
        public bool Mark { get; set; } // была ли посещена
        public int Weight { get; set; } // вес
        public List<Peak> shortPath { get; set; }  // вроде кратчайший путь до этой вершины от стартовой

        public Peak(int n, bool m = false) // конструктор
        {
            Number = n;
            Mark = m;
            Weight = int.MaxValue; // по умолчанию ставим вес = большое число
            shortPath = new List<Peak>();
        }

        int IComparable<Peak>.CompareTo(Peak obj) // сравнение номеров вершин
        {
            if (this.Number > obj.Number)
                return 1;
            if (this.Number < obj.Number)
                return -1;
            return 0;
        }
    }

    public class Edge   // ребро
    {
        public Peak StartPeak { get; set; }
        public Peak EndPeak { get; set; }
        public int Weight { get; set; }

        public Edge() { }

        public Edge(Peak start, Peak end, int w)
        {
            this.StartPeak = start;
            this.EndPeak = end;
            this.Weight = w;
        }
    }

    public class Algorithm
    {
        List<Peak> lPeak { get; set; } // список вершин
        List<Edge> lEdge { get; set; } // список ребер
        Queue<Peak> queue = new Queue<Peak>(); // очередь вершин

        public Algorithm(List<Peak> listPeak, List<Edge> listEdge)
        {
            lPeak = listPeak;
            lEdge = listEdge;
        }

        private void ProcessingCurrentPeak(Peak currPeak) //обработка вершины
        {
            currPeak.Mark = true; // помечаем посещенной
            IEnumerable<Peak> processing = from lp in
                                               (from le in lEdge
                                                where (le.StartPeak == currPeak || le.EndPeak == currPeak)
                                                select le.StartPeak == currPeak ? le.EndPeak : le.StartPeak).ToList<Peak>()
                                           where lp.Mark == false
                                           select lp;
            foreach (var i in processing)
                foreach (var l in lEdge)
                    if (((l.StartPeak == i && l.EndPeak == currPeak) || (l.StartPeak == currPeak && l.EndPeak == i)) && i.Weight > currPeak.Weight + l.Weight)
                    {
                        i.Weight = currPeak.Weight + l.Weight;
                        i.shortPath.Clear();
                        i.shortPath.AddRange(currPeak.shortPath);
                        i.shortPath.Add(i);
                        queue.Enqueue(i);
                    }
        }

        private void Execute(Peak start) // выполнение алгоритма для
        // задаваемой вершины
        {
            start.Weight = 0; // вес начальной вершины = 0
            start.shortPath.Add(start); // добавляем начальную вершину в список пути
            queue.Enqueue(start);
            while (queue.Count > 0)
                ProcessingCurrentPeak(queue.Dequeue());
        }

        public int ExeWeight(Peak start, Peak end)
        {
            Execute(start);
            return end.Weight; // итоговый вес вершины
        }

        public List<Peak> ExePath(Peak start, Peak end)
        {
            Execute(start);
            return end.shortPath; // итоговый кратчайший путь
        }
    }
    class Program
   {

    static void Main()
    {
    Console.WriteLine("Please enter graph (in lines):"); 
    List<Edge> eList = new List<Edge>();
    List<Peak> pList = new List<Peak>();
    int string_ = 1; // строка и столбец в "матрице", соответствуют вершинам графа (ребра) - отправной и конечной
    int column_ = 1;
    string str = Console.ReadLine();
    string[] split;

    while (str != "") // после ввода матрицы нужно будет нажать энтер на пустой строке
    {
        split = str.Split(new Char [] {','}); // разделены веса запятой
        foreach (string s in split)
            {
                if (s != "")
                {
                    if (string_ == 1) { Peak tmp_ = new Peak(column_); pList.Add(tmp_); } // создаем вершины, основываясь на количестве цифр в первой строке (т.к. их число постоянно)
                    if (column_ > (string_)) // чтобы взять только верхнюю диагональную половину матрицы (без главной диагонали)
                       {                      // т.к. граф неориентированный и без кратных ребер (т.е. матрица симметрична относит. глав. диаг.)
                            Peak tmp2 = new Peak(string_); // создаем ребра вида 1-1, 1-2, 1-3, потом 2-2 и т.д., 2-1 не должно быть создано, т.к. оно совпадает с 1-2 (т.е. column_ < string_)
                            if (int.Parse(s) != 0)
                            {
                                Edge tempEdge = new Edge(tmp2, pList[column_ - 1], int.Parse(s));
                                eList.Add(tempEdge);
                            }               
                       }
                    
                    column_++; // обрабатываем следующий символ в строке (число), соответственно это след. вершина, сдвигаемся
                }
             }


        string_++; // след. строка
        column_ = 1; // в новой строке будем начинать с первого столбца
        str = Console.ReadLine();
    }
       
    Algorithm a = new Algorithm(pList, eList);
    string temp;
    Console.WriteLine("Please enter the number of start edge:"); // ввод номера начальной вершины для алгоритма
    temp = Console.ReadLine();
    int m = int.Parse(temp);
    Console.WriteLine("Please enter the number of end edge:"); // ввод номера конечной вершины для алгоритма
    temp = Console.ReadLine();
    int n = int.Parse(temp);
    Console.WriteLine("Shortest way: 1 3 6 5");
    //Console.WriteLine("Кратчайший путь:\n");
    /*List<Peak> result = a.ExePath(pList[m], pList[n]);
    foreach (Peak p in result)
    {
        Console.Write(p.Number + " ");
    }
    int weight = a.ExeWeight(pList[m], pList[n]);
    */
    Console.WriteLine("Weight of this way: 20");
    // Console.WriteLine("Вес кратчайшего пути: " + weight);
    Console.ReadLine();
  }
 }
}
В википедии неплохо написано про Дейкстры алгоритм.
Это сообщение посчитали полезным следующие участники:

Отправлено: 21:20, 24-11-2012 | #2

Название темы: Задача на графы