我写了这个程序来测试“解决”集合覆盖问题需要多长时间。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using MoreLinq;
namespace SetCover
{
class Program
{
const int maxNumItems = 10000;
const int numSets = 5000;
const int maxItemsPerSet = 300;
static void Main(string[] args)
{
var rand = new Random();
var sets = new List<HashSet<int>>(numSets);
var cover = new List<HashSet<int>>(numSets);
var universe = new HashSet<int>();
HashSet<int> remaining;
var watch = new Stopwatch();
Console.Write("Generating sets...");
for (int i = 0; i < numSets; ++i)
{
int numItemsInSet = rand.Next(1, maxItemsPerSet);
sets.Add(new HashSet<int>());
for (int j = 0; j < numItemsInSet; ++j)
{
sets[i].Add(rand.Next(maxNumItems));
}
}
Console.WriteLine("Done!");
Console.Write("Computing universe...");
foreach (var set in sets)
foreach (var item in set)
universe.Add(item);
Console.WriteLine("Found {0} items.", universe.Count);
watch.Start();
//Console.Write("Removing subsets...");
//int numSetsRemoved = sets.RemoveAll(subset => sets.Any(superset => subset != superset && subset.IsSubsetOf(superset)));
//Console.WriteLine("Removed {0} subsets.", numSetsRemoved);
//Console.Write("Sorting sets...");
//sets = sets.OrderByDescending(s => s.Count).ToList();
//Console.WriteLine("{0} elements in largest set.", sets[0].Count);
Console.WriteLine("Computing cover...");
remaining = universe.ToHashSet();
while (remaining.Any())
{
Console.Write(" Finding set {0}...", cover.Count + 1);
var nextSet = sets.MaxBy(s => s.Intersect(remaining).Count());
remaining.ExceptWith(nextSet);
cover.Add(nextSet);
Console.WriteLine("{0} elements remaining.", remaining.Count);
}
Console.WriteLine("{0} sets in cover.", cover.Count);
watch.Stop();
Console.WriteLine("Computed cover in {0} seconds.", watch.Elapsed.TotalSeconds);
Console.ReadLine();
}
}
public static class Extensions
{
public static HashSet<TValue> Clone<TValue>(this HashSet<TValue> set)
{
var tmp = new TValue[set.Count];
set.CopyTo(tmp, 0);
return new HashSet<TValue>(tmp);
}
public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source)
{
return new HashSet<TSource>(source);
}
}
}
这只是一个贪婪的次优解决方案,但它仍然需要147秒才能运行。我认为然而,这个解决方案应该非常关闭到最佳,所以它应该足够我的目的。我怎么能加快速度呢?
我评论了几行,因为它们弊大于利。 编辑:计算宇宙实际上不应该分开时间......事先可以知道。
答案 0 :(得分:2)
我没有深入研究你的代码/算法的细节,但我会用一些理论来建议你。正如henk评论的那样,为了执行“好”的基准测试,您必须删除所有不需要的代码,并在发布模式下运行您的程序,并进行全面优化和命令行。
然后,请记住您正在运行托管代码:C#(和Java)旨在实现互操作性,而不是性能,而它们仍然是良好的平台。如果你需要性能,你应该尝试用C ++重新实现你的代码,或者,如果你愿意,尝试使用Mono和AOT(提前编译器):它会破坏性能很多
mono --aot=full YourProgram.exe
现在更多关于基准和最佳性:您是否将结果与其他人进行了比较?您是否在同一硬件上运行其他机顶盒算法,或者您可以将硬件与运行相同算法的其他硬件进行比较?
并且......您的解决方案与最佳解决方案有多接近?你能提供[自己]估计吗?关键在于LINQ,我讨厌这是因为你为了简化代码而失去了对代码的控制权。 LINQ的复杂性是什么?如果每个LINQ都是O(n),那么你的算法是O(n ^ 3),但我可能会建议你替换
remaining.Any()
与
remaining.Count > 0
获得复杂程度。
我只是建议,希望得到帮助