Click here to Skip to main content
15,902,492 members
Home / Discussions / Algorithms
   

Algorithms

 
AnswerRe: Spiral Function Pin
Alan Balkany31-Oct-13 11:22
Alan Balkany31-Oct-13 11:22 
QuestionRandom Triangular Matrix Pin
Kyudos28-Oct-13 11:50
Kyudos28-Oct-13 11:50 
AnswerRe: Random Triangular Matrix Pin
BillWoodruff29-Oct-13 5:29
professionalBillWoodruff29-Oct-13 5:29 
GeneralRe: Random Triangular Matrix Pin
Kyudos29-Oct-13 14:01
Kyudos29-Oct-13 14:01 
QuestionPicking persons in a group algorithm Pin
Eduard Keilholz27-Oct-13 21:50
Eduard Keilholz27-Oct-13 21:50 
AnswerRe: Picking persons in a group algorithm Pin
Chris Losinger28-Oct-13 6:01
professionalChris Losinger28-Oct-13 6:01 
SuggestionRe: Picking persons in a group algorithm Pin
Richard Deeming28-Oct-13 12:57
mveRichard Deeming28-Oct-13 12:57 
AnswerRe: Picking persons in a group algorithm Pin
Richard Deeming29-Oct-13 2:45
mveRichard Deeming29-Oct-13 2:45 
Here's another way of thinking about this:

You have an array of values. The index into the array is the zero-based number of the person doing the pointing, and the value is the zero-based index of the person being pointed at. This automatically satisfies the rule that each person can only point to one other person. You then only need to validate that nobody is pointing to themselves, nobody is pointing to a forbidden person, and there are no duplicates.

C#
public struct ForbiddenConnection
{
    private readonly int _source;
    private readonly int[] _destination;
    
    private ForbiddenConnection(int source, int[] destination)
    {
        _source = source;
        _destination = destination;
    }
    
    public static ForbiddenConnection Create(int source, IEnumerable<int> destination)
    {
        return new ForbiddenConnection(source, SortedDistinct(destination).ToArray());
    }
    
    public static ForbiddenConnection Create(int source, params int[] destination)
    {
        return Create(source, destination.AsEnumerable());
    }
    
    private static IEnumerable<int> SortedDistinct(IEnumerable<int> source)
    {
        if (source == null) yield break;
        
        bool started = false;
        int lastItem = 0;
        foreach (int item in source.OrderBy(x => x))
        {
            if (started && item == lastItem) continue;
            
            yield return item;
            lastItem = item;
            started = true;
        }
    }
    
    public int Source
    {
        get { return _source; }
    }
    
    public bool Contains(int destination)
    {
        return _destination != null && Array.BinarySearch(_destination, destination) >= 0;
    }
}

public sealed class GraphGenerator : IEnumerable<IReadOnlyList<int>>
{
    private readonly int _length;
    private readonly IDictionary<int, ForbiddenConnection> _forbidden;
    
    private GraphGenerator(int length, IEnumerable<ForbiddenConnection> forbidden)
    {
        _length = length;
        
        if (forbidden != null)
        {
            _forbidden = forbidden.ToDictionary(fc => fc.Source);
        }
        else
        {
            _forbidden = new Dictionary<int, ForbiddenConnection>(0);
        }
    }
    
    public static GraphGenerator Create(int length, IEnumerable<ForbiddenConnection> forbidden)
    {
        if (length < 2) throw new ArgumentOutOfRangeException("length");
        return new GraphGenerator(length, forbidden);
    }
    
    public static GraphGenerator Create(int length, params ForbiddenConnection[] forbidden)
    {
        return Create(length, forbidden.AsEnumerable());
    }
    
    private bool Validate(IReadOnlyList<int> graph)
    {
        Debug.Assert(graph != null);
        Debug.Assert(graph.Count == _length);
        
        for (int i = 0; i < graph.Count; i++)
        {
            int index = graph[i];
            Debug.Assert(0 <= index && index < _length);
            
            if (index == i)
            {
                Trace.TraceInformation("Node {0} points to itself.", i);
                return false;
            }
            
            ForbiddenConnection forbidden;
            if (_forbidden.TryGetValue(i, out forbidden) && forbidden.Contains(index))
            {
                Trace.TraceInformation("Node {0} cannot point to node {1}.", i, index);
                return false;
            }
            
            for (int j = i + 1; j < graph.Count; j++)
            {
                if (graph[j] == index)
                {
                    Trace.TraceInformation("Nodes {0} and {1} both point to node {2}.", i, j, index);
                    return false;
                }
            }
        }
        
        return true;
    }
    
    public IEnumerator<IReadOnlyList<int>> GetEnumerator()
    {
        // TODO: Return every valid permutation.
    }
    
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}


Now you just need to generate every permutation of indices for your graph, and return those which are valid. Eric Lippert has an excellent seven-part series on generating permutations[^], so we can borrow some of his code:
C#
public struct Permutation : IReadOnlyList<int>
{
    public static readonly Permutation Empty = default(Permutation);
    
    private readonly int[] _value;
    
    private Permutation(Permutation source, int index, int value)
    {
        if (source.Count == 0)
        {
            _value = new[] { value };
        }
        else
        {
            _value = new int[source.Count + 1];
            _value[index] = value;
            
            if (index != 0) 
            {
                Array.Copy(source._value, 0, _value, 0, index);
            }
            if (index != source.Count)
            {
                Array.Copy(source._value, index, _value, index + 1, source.Count - index);
            }
        }
    }
    
    public int Count
    {
        get { return (_value == null) ? 0 : _value.Length; }
    }
    
    public int this[int index]
    {
        get
        {
            if (0 > index || index >= Count) throw new ArgumentOutOfRangeException("index");
            return _value[index];
        }
    }
    
    public IEnumerator<int> GetEnumerator()
    {
        if (_value == null) return Enumerable.Empty<int>().GetEnumerator();
        return _value.AsEnumerable().GetEnumerator();
    }
    
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    
    public static IEnumerable<Permutation> HamiltonianPermutations(int ofSize)
    {
        if (ofSize < 0) throw new ArgumentOutOfRangeException("ofSize");
        return HamiltonianPermutationsIterator(ofSize);
    }
    
    private static IEnumerable<Permutation> HamiltonianPermutationsIterator(int ofSize)
    {
        if (ofSize == 0)
        {
            yield return Empty;
            yield break;
        }
        
        bool forwards = false;
        foreach (var permutation in HamiltonianPermutationsIterator(ofSize - 1))
        {
            for (int index = 0; index < ofSize; index++)
            {
                int insertAt = forwards ? index : ofSize - index - 1;
                yield return new Permutation(permutation, insertAt, ofSize - 1);
            }
            
            forwards = !forwards;
        }
    }
}


This leads to a very simple implementation of the GraphGenerator.GetEnumerator method:
C#
public IEnumerator<IReadOnlyList<int>> GetEnumerator()
{
    return Permutation.HamiltonianPermutations(_length)
        .Cast<IReadOnlyList<int>>()
        .Where(Validate)
        .GetEnumerator();
}


Using it would look something like this:
C#
var generator = GraphGenerator.Create(8,
    ForbiddenConnection.Create(0, 1), // Person A cannot point to person B
    ForbiddenConnection.Create(1, 0)  // Person B cannot point to person A
);

if (!generator.Any())
{
    // Configuration is not possible
}


For eight people with no forbidden connections, there are 14833 possible graphs. On my computer, enumerating every possible graph takes approximately 0.11 seconds, which should be fast enough for most purposes.



"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer


GeneralRe: Picking persons in a group algorithm Pin
BillWoodruff29-Oct-13 5:22
professionalBillWoodruff29-Oct-13 5:22 
Questionusing genetic algorithms to improve voice commands recognition Pin
Member 997361615-Oct-13 0:24
Member 997361615-Oct-13 0:24 
QuestionHow to Remove duplicate files rapidly? Pin
happy liu7-Oct-13 22:35
professionalhappy liu7-Oct-13 22:35 
AnswerRe: How to Remove duplicate files rapidly? Pin
jschell8-Oct-13 10:28
jschell8-Oct-13 10:28 
GeneralRe: How to Remove duplicate files rapidly? Pin
happy liu8-Oct-13 14:51
professionalhappy liu8-Oct-13 14:51 
AnswerRe: How to Remove duplicate files rapidly? Pin
Manfred Rudolf Bihy9-Oct-13 0:14
professionalManfred Rudolf Bihy9-Oct-13 0:14 
GeneralRe: How to Remove duplicate files rapidly? Pin
happy liu9-Oct-13 16:44
professionalhappy liu9-Oct-13 16:44 
GeneralRe: How to Remove duplicate files rapidly? Pin
Manfred Rudolf Bihy9-Oct-13 16:51
professionalManfred Rudolf Bihy9-Oct-13 16:51 
GeneralRe: How to Remove duplicate files rapidly? Pin
happy liu9-Oct-13 16:52
professionalhappy liu9-Oct-13 16:52 
GeneralRe: How to Remove duplicate files rapidly? Pin
saephoed8-Jan-14 12:50
saephoed8-Jan-14 12:50 
AnswerRe: How to Remove duplicate files rapidly? Pin
Kornfeld Eliyahu Peter9-Oct-13 0:50
professionalKornfeld Eliyahu Peter9-Oct-13 0:50 
GeneralRe: How to Remove duplicate files rapidly? Pin
happy liu9-Oct-13 16:42
professionalhappy liu9-Oct-13 16:42 
GeneralRe: How to Remove duplicate files rapidly? Pin
Kornfeld Eliyahu Peter10-Oct-13 1:10
professionalKornfeld Eliyahu Peter10-Oct-13 1:10 
AnswerRe: How to Remove duplicate files rapidly? Pin
Chris Losinger10-Oct-13 5:05
professionalChris Losinger10-Oct-13 5:05 
GeneralRe: How to Remove duplicate files rapidly? Pin
Kornfeld Eliyahu Peter10-Oct-13 5:42
professionalKornfeld Eliyahu Peter10-Oct-13 5:42 
GeneralRe: How to Remove duplicate files rapidly? Pin
Manoj Kumar Rai13-Oct-13 9:26
professionalManoj Kumar Rai13-Oct-13 9:26 
AnswerRe: How to Remove duplicate files rapidly? Pin
theafien3-Dec-13 3:58
theafien3-Dec-13 3:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.