2011-09-24 18 views
5

Tek bir LINQ sorgusunda en yakın komşu algoritması kullanarak satıcı problemi çözümü için çözüm?

List<Point> cities = /* ... */ ; 
double distance(Point a, Point b) { /* ... */ }; 

cities indekslerinin bir List<int> olarak en yakın komşu algoritması tarafından seyyar satıcı en kısa rota döndüren bir tek LINQ sorgusu var

Verilen?

+0

döngüler için kullanan daha okunabilir olduğunu düşünüyorum bile "En yakın komşu" tarafından "bir sonraki en yakın citiy'e git" diye düşünüyorsunuz? Peki bunu bir linq-zinciri ile sureleyebilirsin ama bu neredeyse * ödevi * gibi okudu ... – Carsten

cevap

3

Her şeyi tek bir sorguda yapabileceğinizi düşünmüyorum, algoritmaların bazı bölümleri ayrı ayrı uygulanmalıdır.

Permutations uzatma yöntemi olarak tanımlanır
var bestPath = 
    cities.Permutations() 
     .MinBy(
     steps => steps.Aggregate(
        new { Sum = 0, Previous = default(Point) }, 
        (acc, c) => 
         new 
         { 
          Sum = acc.Sum + (acc.Previous != null ? Distance(c, acc.Previous) : 0), 
          Previous = c 
         }, 
        acc => acc.Sum)); 

şu: Of

public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> source) 
{ 
    var query = 
     from item in source 
     from others in source.SkipOnce(item).Permutations() 
     select new[] { item }.Concat(others); 
    return query.DefaultIfEmpty(Enumerable.Empty<T>()); 
} 

public static IEnumerable<T> SkipOnce<T>(this IEnumerable<T> source, T itemToSkip) 
{ 
    bool skipped = false; 
    var comparer = EqualityComparer<T>.Default; 
    foreach (var item in source) 
    { 
     if (!skipped && comparer.Equals(item, itemToSkip)) 
      skipped = true; 
     else 
      yield return item; 
    } 
} 

İşte

tüm şehir permütasyon inceler ve tüm şehirleri ziyaret kısa yolu döndüren bir kaba kuvvet uygulaması var Elbette bu sorunu çözmek için çok daha iyi yaklaşımlar vardır, ancak bu çalışır ... Çoğu tek bir sorguda, ayrı ayrı uygulanan tek parçalar, eldeki sorunlara özgü değildir ve diğer görevler için yeniden kullanılabilir.

DÜZENLEME: oops, Ben sadece standart olmayan MinBy yöntemini kullandım; Bulabileceğiniz o in the MoreLinq project

+0

Thomas, @digEmAll, ikinize de teşekkürler. İki eşit derecede iyi cevap arasında seçim yapamadım, böylece ilkini işaretledim. – ChrisJJ

+0

@ChrisJJ, aslında digEmAll'ın cevabı size sorduğunuz şeye daha yakın; Algoritmam "en yakın komşuluğu" sezgisel kullanmaz (tüm sezgisel kullanır, sadece her yolu dener ve en iyisini döndürür) –

2

Sadece tek LINQ sorgusunda Yakın Komşu algoritması gerekiyorsa, bu şekilde yapabilirsiniz:

var nearestNeighTour = cities.Skip(1).Aggregate(
new List<int>() { 0 }, 
(list, curr) => 
{ 
    var lastCity = cities[list.Last()]; 
    var minDist = Enumerable.Range(0, cities.Count).Where(i => !list.Contains(i)).Min(cityIdx => distance(lastCity, cities[cityIdx])); 
    var minDistCityIdx = Enumerable.Range(0,cities.Count).Where(i => !list.Contains(i)).First(cityIdx => minDist == distance(lastCity, cities[cityIdx])); 
    list.Add(minDistCityIdx); 
    return list; 
}); 

Ben

İlgili konular