【问题标题】:Creating groups based on previous data根据以前的数据创建组
【发布时间】:2014-03-21 19:16:30
【问题描述】:

我正在尝试让我的应用确定将 20 名高尔夫球手分成四人一组的最佳解决方案。

我有数据显示高尔夫球手的比赛时间、日期以及组中的其他人。

我希望由没有一起打球的高尔夫球手组成的小组,或者当所有人都一起打球时,他们一起打球的时间最长。换句话说,我想要由一段时间没有一起玩过的玩家组成的组,而不是上次一起玩的玩家。

创建一个 20 的排列列表!确定最低组合效果不佳。

还有其他我没有想到的解决方案吗?

【问题讨论】:

  • 当你说有一段时间没有一起玩的时候,是把所有玩家的平均分算出来吗?

标签: java math combinations permutation


【解决方案1】:

@Salix-alba 的回答可以帮助您入门。基本上,您需要一种方法来计算您的高尔夫团体成员已经一起度过了多少时间。为了说明,我假设您有一种方法可以确定两个高尔夫球手一起度过了多少时间。算法可以总结为:

  1. 计算每组 4 名高尔夫球手在一起的总时间(请参阅 Salix-alba 的答案),以有序的方式存储结果。

  2. 选择在一起时间最少的 4 名高尔夫球手作为第一组。

  3. 继续从已排序的可能组列表中选择组,这样下一个选择的组中没有任何成员是之前选择的任何组的成员

  4. 当所有高尔夫球手都有一组时暂停,这总是在您用完可能的组合之前发生。

顺便说一句,不答应编译示例(我直接在回答窗口写了):

假设您有一个方法time(a,b),其中ab 是高尔夫球手的身份,结果是两个高尔夫球手在一起的时间。

假设我们将使用 TreeMap> 以排序方式跟踪与组关联的“权重”。

现在,让我们使用上述假设来构建我们组的权重:

TreeMap<Integer,Collection<Integer>> options = new TreeMap<Integer, Collection<Integer>>(); 
for(int i=0;i<17;++i) {
    for(int j=i+1;j<18;++j) {
        for(int k=j+1;k<19;++k) {
            for(int l=k+1;l<20;++l) {
                Integer timeTogether = time(i,j) + time(i,k) + time(i,l) + time(j,k) + time(j,l)+time(k,l);
                Collection<Integer> group = new HashSet<Integer>();
                group.add(i);
                group.add(j);
                group.add(k);
                group.add(l);
                options.put(timeTogether, group);
            }
        }
    }
}
Collection<Integer> golferLeft = new HashSet<Integer>(); // to quickly determine if we should consider a group.
for(int a=0; a < maxGolfers, a++) {
    golferLeft.add(a);
}

Collection<Collection<Integer>> finalPicks = new ArrayList<Collection<Integer>>();
do{
    Map.Entry<Integer, Collection<Integer>> least = options.pollFirstEntry();
    if (least != null && golferLeft.containsAll(least.getValue()) {
        finalPicks.add(least.getValue());
        golferLeft.removeAll(least.getValue());
    }
}while (golferLeft.size() > 0 && least != null);

在最后一个循环结束时,finalPicks 将有多个集合,每个集合代表一个播放组。

显然,您可以调整权重函数以获得不同的结果 - 假设您希望尽量减少小组成员一起玩的时间。在这种情况下,不要使用游戏时间,而是用一些任意大但合理的值来总结组中每个成员自上次游戏以来的时间,以表明他们是否从未玩过,而不是找到最小的组,而是找到最大的组。以此类推。

我希望这是一本有用的入门书!

【讨论】:

    【解决方案2】:

    应该有 20 个 C 4 可能的分组,即 4845。使用四个嵌套的 for 循环应该可以很容易地生成这些组合。

    int count = 0;
    for(int i=0;i<17;++i) {
        for(int j=i+1;j<18;++j) {
            for(int k=j+1;k<19;++k) {
                for(int l=k+1;l<20;++l) {
                    System.out.println(""+i+"\t"+j+"\t"+k+"\t"+l);
                    ++count;
                }
            }
        }
    }
    System.out.println("Count "+count);
    

    您可以快速循环所有这些,并使用一些目标函数来锻炼,这是最优化的分组。您的问题定义有点模糊,所以我不确定如何判断哪个是最佳组合。

    这只是从 20 名高尔夫球手中挑选 4 名高尔夫球手的数量,你真的需要 5 组 4 人,我认为是 20C4 * 16C4 * 12C4 * 8C4 即 305,540,235,000。尽管您可能需要等待几分钟,但这仍处于详尽计算的范围内。

    另一种方法可能是概率方法。只需随机选择组,拒绝非法组合和不符合您标准的组合。继续选择随机组,直到找到足够好的组为止。

    【讨论】:

    • 我推荐一个简单的求和指标,你可以将每个 4-clique 中所有高尔夫球手以前一起花费的时间相加,例如:(i,j)+(i,k)+(i,l)+(j,k)+(j,l)+(k,l)。将时间和集团成员存储在排序列表中。完成计算后,选择在一起时间最短的一组作为起始组。然后,要查找下一个组,请查找与任何先前选择的组没有共同成员的下一个最短时间。在您完成所有 4845 个组合之前,您会发现您的分组非常喜欢新的或不常见的分组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 2016-07-14
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多