Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 电影院朋友分组算法_C#_Algorithm - Fatal编程技术网

C# 电影院朋友分组算法

C# 电影院朋友分组算法,c#,algorithm,C#,Algorithm,我给你准备了一个脑筋急转弯-它不像听起来那么简单,所以请阅读并尝试解决这个问题。在你问这是不是家庭作业之前——不是!我只是想看看是否有一个优雅的方法来解决这个问题。问题是: 很多朋友想去看电影,想坐下来 在最好的可用组中。最好的情况是大家坐在一起 最糟糕的情况是每个人都独自坐着。与更多组相比,更少的组更受欢迎。优先选择平衡组(3+3比4+2更优先)。 独自坐着是最不可取的 输入是去电影院的人数,输出应为整数数组,其中包含: 有序组合(最优先的是第一个) 每组人数 下面是一些去电影院的人数示例

我给你准备了一个脑筋急转弯-它不像听起来那么简单,所以请阅读并尝试解决这个问题。在你问这是不是家庭作业之前——不是!我只是想看看是否有一个优雅的方法来解决这个问题。问题是:

很多朋友想去看电影,想坐下来 在最好的可用组中。最好的情况是大家坐在一起 最糟糕的情况是每个人都独自坐着。与更多组相比,更少的组更受欢迎。优先选择平衡组(3+3比4+2更优先)。 独自坐着是最不可取的

输入是去电影院的人数,输出应为整数数组,其中包含:

  • 有序组合(最优先的是第一个)
  • 每组人数
下面是一些去电影院的人数示例,以及这些人可以坐的首选组合列表:

  • 1人:1
  • 2人:2,1+1
  • 3人:3、2+1、1+1+1
  • 4人:4、2+2、3+1、2+1+1、1+1+1+1
  • 5人:5、3+2、4+1、2+2+1、3+1+1、2+1+1+1、1+1+1+1
  • 6人:6、3+3、4+2、2+2+2、5+1、3+2+1、2+2+1+1、2+1+1+1、1+1+1+1
超过7人的例子在组合中爆炸,但我想你现在明白了

问题是:解决这个问题的算法看起来像什么?
我选择的语言是C,所以如果你能用C给出答案,那就太棒了

假设我正确地理解了您,您可以递归地执行此操作

  • 对于一个人,唯一的分组是
    1
  • 对于
    n
    人,分组都是针对
    1
    人和剩余
    n-1
    人的分组,以及
    2
    人和剩余
    n-2
    人的分组,依此类推

一旦你有了可能的分组列表,你就可以根据你想要的任何标准按“可取性”对它们进行排序。

我认为你需要递归地进行排序,但你需要确保你不会一次又一次地对同一组进行分区。这将给您指数级的执行时间。在我的解决方案中,看起来我有O(n*n)(您可以为我验证;),请参见下面的结果。另一件事是你提到的欲望函数。我不知道这样一个函数会是什么样子,但是你可以比较两个分区。e、 分区1+1+2+4不如1+2+2+3理想,因为它有两个“一”。一般规则可以是“如果一个分区的分组人数与另一个分区的分组人数相同,则该分区不太可取”。有道理,坐在一起的人越多越好。我的解决方案采用这种方法来比较两种可能的分组,我得到了您想要得到的结果。让我先给你看一些结果,然后是代码

        var sut = new BrainTeaser();

        for (int n = 1; n <= 6; n++) {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("{0} person{1}: ", n, n > 1 ? "s" : "");

            var array = sut.Solve(n).Select(x => x.ToString()).ToArray();
            sb.AppendLine(string.Join(", ", array));

            Console.WriteLine(sb.ToString());
        }
var sut=new braintaster();
对于(int n=1;n1?“s”:“);
var array=sut.Solve(n).Select(x=>x.ToString()).ToArray();
sb.AppendLine(string.Join(“,”数组));
Console.WriteLine(sb.ToString());
}
1人:1

2人:2,1+1

3人:3、1+2、1+1+1

4人:4、2+2、1+3、1+1+2、1+1+1+1

5人:5、2+3、1+4、1+2+2、1+1+3、1+1+1+2、1+1+1+1+1

6人:6、3+3、2+4、2+2+2、1+5、1+2+3、1+1+4、1+1+2+2、1+1+1+3、1+1+1+2、1+1+1+1+1

性能看起来是O(n*n):

var sut=new braintaster();
对于(int n=1;nx)){
收益率可能组合;
}
}
私有void AddAllPartitions(可能分组,哈希集可能分组){
for(int i=0;ix.ToArray();
sum=FriendsGroup.sum();
}
公共整数和{
获取{返回和;}
}
/// 
///确定哪个组更可取。例如:
//考虑G1:1+2+3+4 vs g2:1+1+2+2+4
///按出现次数对每个序列进行分组:
/// 
///组| g1 | g2
/// --------|-------------
/// 1       | 1    | 2
/// ----------------------
/// 2       | 1    | 2
/// ----------------------
/// 3       | 1    | 0
/// ----------------------
/// 4       | 1    | 1
/// ----------------------
/// 
///序列“g1”的得分应为“更高”,因为它具有“更少的”元素(最不理想的)元素。
/// 
///如果两个序列都有相同数量的“一”,我们会比较“二”。
/// 
/// 
/// 
/// 
公共int比较(可能组合其他){
var thisGroup=(从FriendsGroup组n中的n乘以n)。ToDictionary(x=>x.Key,
x=>x.Count());
var otherGroup=(从other.friendsInGroup组n中的n乘以n)。ToDictionary(x=>x.Key,
x=>x.Count());
返回哪个组更好(此组,
var sut = new BrainTeaser();

 for (int n = 1; n <= 40; n++) {
   Stopwatch watch = new Stopwatch();
   watch.Start();
   var count = sut.Solve(n).Count();
   watch.Stop();
   Console.WriteLine("Problem solved for {0} friends in {1} ms. Number of solutions {2}", n, watch.ElapsedMilliseconds, count);
}

Problem solved for 1 friends in 17 ms. Number of solutions 1
Problem solved for 2 friends in 49 ms. Number of solutions 2
Problem solved for 3 friends in 2 ms. Number of solutions 3
Problem solved for 4 friends in 1 ms. Number of solutions 5
Problem solved for 5 friends in 0 ms. Number of solutions 7
Problem solved for 6 friends in 2 ms. Number of solutions 11
Problem solved for 7 friends in 0 ms. Number of solutions 15
Problem solved for 8 friends in 0 ms. Number of solutions 22
Problem solved for 9 friends in 1 ms. Number of solutions 30
Problem solved for 10 friends in 1 ms. Number of solutions 42
Problem solved for 11 friends in 4 ms. Number of solutions 56
Problem solved for 12 friends in 4 ms. Number of solutions 77
Problem solved for 13 friends in 7 ms. Number of solutions 101
Problem solved for 14 friends in 9 ms. Number of solutions 135
Problem solved for 15 friends in 15 ms. Number of solutions 176
Problem solved for 16 friends in 21 ms. Number of solutions 231
Problem solved for 17 friends in 30 ms. Number of solutions 297
Problem solved for 18 friends in 43 ms. Number of solutions 385
Problem solved for 19 friends in 61 ms. Number of solutions 490
Problem solved for 20 friends in 85 ms. Number of solutions 627
Problem solved for 21 friends in 117 ms. Number of solutions 792
Problem solved for 22 friends in 164 ms. Number of solutions 1002
Problem solved for 23 friends in 219 ms. Number of solutions 1255
Problem solved for 24 friends in 300 ms. Number of solutions 1575
Problem solved for 25 friends in 386 ms. Number of solutions 1958
Problem solved for 26 friends in 519 ms. Number of solutions 2436
Problem solved for 27 friends in 677 ms. Number of solutions 3010
Problem solved for 28 friends in 895 ms. Number of solutions 3718
Problem solved for 29 friends in 1168 ms. Number of solutions 4565
Problem solved for 30 friends in 1545 ms. Number of solutions 5604
Problem solved for 31 friends in 2025 ms. Number of solutions 6842
Problem solved for 32 friends in 2577 ms. Number of solutions 8349
Problem solved for 33 friends in 3227 ms. Number of solutions 10143
Problem solved for 34 friends in 4137 ms. Number of solutions 12310
Problem solved for 35 friends in 5300 ms. Number of solutions 14883
Problem solved for 36 friends in 6429 ms. Number of solutions 17977
Problem solved for 37 friends in 8190 ms. Number of solutions 21637
Problem solved for 38 friends in 10162 ms. Number of solutions 26015
Problem solved for 39 friends in 12643 ms. Number of solutions 31185
public class BrainTeaser {
    /// <summary>
    /// The possible groupings are returned in order of the 'most' desirable first. Equivalent groupings are not returned (e.g. 2 + 1 vs. 1 + 2). Only one representant
    /// of each grouping is returned (ordered ascending. e.g. 1 + 1 + 2 + 4 + 5)
    /// </summary>
    /// <param name="numberOfFriends"></param>
    /// <returns></returns>
    public IEnumerable<PossibleGrouping> Solve(int numberOfFriends) {
        if (numberOfFriends == 1) {
            yield return new PossibleGrouping(1);
            yield break;
        }
        HashSet<PossibleGrouping> possibleGroupings = new HashSet<PossibleGrouping>(new PossibleGroupingComparer());
        foreach (var grouping in Solve(numberOfFriends - 1)) {
            // for each group we create 'n+1' new groups 
            // 1 + 1 + 2 + 3 + 4 
            // Becomes
            //      (1+1) + 1 + 2 + 3 + 4  we can add a friend to the first group
            //      1 + (1+1) + 2 + 3 + 4  we can add a friend to the second group
            //      1 + 1 + (2+1) + 3 + 4  we can add a friend to the third group
            //      1 + 1 + 2 + (3+1) + 4  we can add a friend to the forth group
            //      1 + 1 + 2 + 3 + (4+1) we can add a friend to the fifth group
            //      (1 + 1 + 2 + 3 + 4) + 1  friend has to sit alone

            AddAllPartitions(grouping, possibleGroupings);
        }
        foreach (var possibleGrouping in possibleGroupings.OrderByDescending(x => x)) {
            yield return possibleGrouping;
        }
    }

    private void AddAllPartitions(PossibleGrouping grouping, HashSet<PossibleGrouping> possibleGroupings) {
        for (int i = 0; i < grouping.FriendsInGroup.Length; i++) {
            int[] newFriendsInGroup = (int[]) grouping.FriendsInGroup.Clone();
            newFriendsInGroup[i] = newFriendsInGroup[i] + 1;
            possibleGroupings.Add(new PossibleGrouping(newFriendsInGroup));
        }
        var friendsInGroupWithOneAtTheEnd = grouping.FriendsInGroup.Concat(new[] {1}).ToArray();
        possibleGroupings.Add(new PossibleGrouping(friendsInGroupWithOneAtTheEnd));
    }
}

/// <summary>
/// A possible grouping of friends. E.g.
/// 1 + 1 + 2 + 2 + 4 (10 friends). The array is sorted by the least friends in an group.
/// </summary>
public class PossibleGrouping : IComparable<PossibleGrouping> {
    private readonly int[] friendsInGroup;

    public int[] FriendsInGroup {
        get { return friendsInGroup; }
    }

    private readonly int sum;

    public PossibleGrouping(params int[] friendsInGroup) {
        this.friendsInGroup = friendsInGroup.OrderBy(x => x).ToArray();
        sum = friendsInGroup.Sum();
    }

    public int Sum {
        get { return sum; }
    }

    /// <summary>
    /// determine which group is more desirable. Example:
    /// Consider g1: 1 + 2 + 3 + 4 vs g2: 1 + 1 + 2 + 2 + 4  
    /// Group each sequence by the number of occurrences:
    /// 
    /// group   | g1   | g2
    /// --------|-------------
    /// 1       | 1    | 2
    /// ----------------------
    /// 2       | 1    | 2
    /// ----------------------
    /// 3       | 1    | 0
    /// ----------------------
    /// 4       | 1    | 1
    /// ----------------------
    /// 
    /// Sequence 'g1' should score 'higher' because it has 'less' 'ones' (least desirable) elements. 
    /// 
    /// If both sequence would have same number of 'ones', we'd compare the 'twos'.
    /// 
    /// </summary>
    /// <param name="other"></param>
    /// <returns></returns>
    public int CompareTo(PossibleGrouping other) {
        var thisGroup = (from n in friendsInGroup group n by n).ToDictionary(x => x.Key,
                                                                             x => x.Count());

        var otherGroup = (from n in other.friendsInGroup group n by n).ToDictionary(x => x.Key,
                                                                                    x => x.Count());

        return WhichGroupIsBetter(thisGroup, otherGroup);
    }

    private int WhichGroupIsBetter(IDictionary<int, int> thisGroup, IDictionary<int, int> otherGroup) {
        int maxNumberOfFriendsInAGroups = Math.Max(thisGroup.Keys.Max(), otherGroup.Keys.Max());

        for (int numberOfFriendsInGroup = 1;
             numberOfFriendsInGroup <= maxNumberOfFriendsInAGroups;
             numberOfFriendsInGroup++) {
            // zero means that the current grouping does not contain a such group with 'numberOfFriendsInGroup'
            // in the example above, e.g. group '3'
            int thisNumberOfGroups = thisGroup.ContainsKey(numberOfFriendsInGroup)
                                         ? thisGroup[numberOfFriendsInGroup]
                                         : 0;
            int otherNumberOfGroups = otherGroup.ContainsKey(numberOfFriendsInGroup)
                                          ? otherGroup[numberOfFriendsInGroup]
                                          : 0;

            int compare = thisNumberOfGroups.CompareTo(otherNumberOfGroups);

            if (compare != 0) {
                // positive score means that the other group has more occurrences. e.g. 'this' group might have 2 groups with each 2 friends,
                // but the other solution might have 3 groups with each 2 friends. It's obvious that (because both solutions must sum up to the same value)
                // this 'solution' must contain a grouping with more than 3 friends which is more desirable.
                return -compare;
            }
        }
        // they must be 'equal' in this case.
        return 0;
    }

    public override string ToString() {
        return string.Join("+", friendsInGroup.Select(x => x.ToString()).ToArray());
    }
}

public class PossibleGroupingComparer : EqualityComparer<PossibleGrouping> {
    public override bool Equals(PossibleGrouping x, PossibleGrouping y) {
        return x.FriendsInGroup.SequenceEqual(y.FriendsInGroup);
    }

    /// <summary>
    /// may not be the best hashcode function. for alternatives look here: http://burtleburtle.net/bob/hash/doobs.html
    /// I got this code from here: http://stackoverflow.com/questions/3404715/c-sharp-hashcode-for-array-of-ints
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public override int GetHashCode(PossibleGrouping obj) {
        var array = obj.FriendsInGroup;

        int hc = obj.FriendsInGroup.Length;
        for (int i = 0; i < array.Length; ++i) {
            hc = unchecked(hc*314159 + array[i]);
        }
        return hc;
    }
}
    public static List<List<int>> EnumerateAll(int n)
    {
        /* Fastest known algorithim for enumerating partitons
         * (not counting the re-ordering that I added)
         * Based on the Python code from http://homepages.ed.ac.uk/jkellehe/partitions.php
         */
        List<List<int>> lst = new List<List<int>>();
        int[] aa = new int[n + 1];
        List<int> a = new List<int>(aa.ToList<int>());
        List<int> tmp;
        int k = 1;

        a[0] = 0;
        int y = n - 1;

        while (k != 0)
        {
            int x = a[k - 1] + 1;
            k -= 1;
            while (2 * x <= y)
            {
                a[k] = x;
                y -= x;
                k += 1;
            }
            int l = k + 1;
            while (x <= y)
            {
                a[k] = x;
                a[l] = y;

                // copy just the part that we want
                tmp = (new List<int>(a.GetRange(0, k + 2)));

                // insert at the beginning to return partions in the expected order
                lst.Insert(0, tmp);
                x += 1;
                y -= 1;
            }
            a[k] = x + y;
            y = x + y - 1;

            // copy just the part that we want
            tmp = (new List<int>(a.GetRange(0, k + 1)));

            // insert at the beginning to return partions in the expected order
            lst.Insert(0, tmp);
        }

        return lst;
    }
    /// <summary>
    /// ReOrders a list of partitons placing those with the smallest groups last
    ///   NOTE: this routine assumes that each partitoning lists the smallest 
    ///   integers *first*.
    /// </summary>
    public static IList<List<int>> ReOrderPartitions(IList<List<int>> source)
    {
        // the count is used in several places
        long totalCount= source.Count;
        long k = 0;     // counter to keep the keys unique

        SortedList<long, List<int>> srt = new SortedList<long, List<int>>(source.Count);

        foreach (List<int> prt in source)
        {
            srt.Add(-(prt[0] * totalCount) + k, prt);
            k++;
        }

        return srt.Values;
    }
    private void ListPreferredPartitons(int n, ListBox listOut)
    {
        IList<List<int>> pts = Partitions.EnumerateAll(n);
        pts = Partitions.ReOrderPartitions(pts);

        listOut.Items.Clear();

        foreach (List<int> prt in pts)
        {
            // reverse the list, so that the largest integers will now be first.
            prt.Reverse();
            string lin = "";
            foreach (int k in prt)
            {
                if (lin.Length > 0) lin += ", ";
                lin += k.ToString();
            }
            listOut.Items.Add(lin);
        }
    }