【问题标题】:Population segmentation algorithm人口分割算法
【发布时间】:2011-08-05 20:28:43
【问题描述】:

我有 50 个有序整数 (1,2,3,..,50),我正在寻找一种通用的方法来将其分割为“n”个方式(“n”是从 1 开始的截止点数到 25) 保持元素的顺序。

例如,对于 n=1(一个截止点),有 49 种可能的分组选择([1,2-49]、[1-2,3-50]、[1-3,4-50]、 ...)。对于 n=2(两个截止点),分组备选方案如下:[1,2,3-50], [1,2-3,4-50],...

您能否推荐任何通用算法来有效地完成此任务?

谢谢, 克里斯


感谢大家的反馈。我审查了你所有的 cmets,我正在研究一个通用的解决方案,它将返回所有数字的所有组合(例如,[1,2,3-50],[1,2-3,4-50],...)分界点。

再次感谢, 克里斯

【问题讨论】:

  • 为什么在这么少的人口中需要效率?暴力破解!
  • @Emilio:看起来没那么小,但如果他想要所有这些,我怀疑还有其他方法。
  • 您在寻找什么?所有可能切片的列表?随机一个?
  • 这里有类似的问题:stackoverflow.com/questions/4563523/…

标签: algorithm combinatorics


【解决方案1】:

令序列长度为N,切片数为n

当您注意到,选择一个切片到 n 个切片时,这个问题就变得更容易了,这相当于从N - 1 可能的分割点中选择n - 1(一个分割点位于序列中的每两个数字之间)。因此有(N - 1 choose n - 1) 这样的切片。

要生成所有切片(到 n 个切片),您必须从 1 to N - 1 生成数字的所有 n - 1 元素子集。

这个问题的具体算法放在这里:How to iteratively generate k elements subsets from a set of size n in java?

【讨论】:

    【解决方案2】:

    您是否需要截止值,或者您只是在计算它们。如果你只是要数他们,那很简单:

    1 个截止 = (n-1) 个选项

    2 个截止点 = (n-1)*(n-2)/2 个选项

    3 个截止点 = (n-1)(n-2)(n-3)/4 个选项

    你可以在这里看到模式

    如果您确实需要截止,那么您必须实际执行循环,但由于 n 非常小,Emilio 是对的,只需蛮力即可。

    1 个截止点

    for(i=1,i<n;++i)
      cout << i;
    

    2 个截止点

    for(i=1;<i<n;++i)
      for(j=i+1,j<n;++j)
        cout << i << " " << j;
    

    3 个截止点

    for(i=1;<i<n;++i)
      for(j=i+1,j<n;++j)
        for(k=j+1,k<n;++k)
          cout << i << " " << j << " " << k;
    

    再次,您可以看到模式

    【讨论】:

      【解决方案3】:

      所以你想以所有可能的方式从 49 个选项中选择 25 个分割点。有很多知名的algorithms 可以做到这一点。

      我想提请您注意这个问题的另一面。有 49!/(25!*(49-25)!) = 63 205 303 218 876 >= 2^45 ~= 10^13 个不同的combinations。所以如果要存储的话,需要的内存量是32TB * sizeof(Combination)。我猜它会通过 1 PB 标记。

      现在假设您要动态处理生成的数据。让optimistic 假设您每秒可以处理 100 万个组合(这里我假设没有并行化)。所以这个任务需要 10^7 秒 = 2777 小时 = 115 天。

      这个问题比乍看起来更复杂。如果你想在家里合理的时间解决,我的建议是改变策略或者等待量子计算机的推进。

      【讨论】:

        【解决方案4】:

        这将生成一个包含所有范围的数组,但我警告你,由于大量结果(50 个元素和 3 个拆分为 49*48*47=110544)我没有' 甚至没有尝试编译它,所以可能有错误,但这是我使用的一般算法。

        typedef std::vector<int>::iterator iterator_t;
        typedef std::pair<iterator_t, iterator_t> range_t;
        typedef std::vector<range_t> answer_t;
        answer_t F(std::vector<int> integers, int slices) {
            answer_t prev;  //things to slice more
            answer_t results; //thin
            //initialize results for 0 slices
            results.push_back(answer(range(integers.begin(), integers.end()), 1));
            //while there's still more slicing to do
            while(slices--) {  
                //move "results" to the "things to slice" pile
                prev.clear(); 
                prev.swap(results); 
                //for each thing to slice
                for(int group=0; group<prev.size(); ++group) { 
                    //for each range
                    for(int crange=0; crange<prev[group].size(); ++crange) { 
                        //for each place in that range
                        for(int newsplit=0; newsplit<prev[group][crange].size(); ++newsplit) { 
                            //copy the "result"
                            answer_t cur = prev[group];
                            //slice it
                            range_t L = range(cur[crange].first, cur[crange].first+newsplit);
                            range_t R = range(cur[crange].first+newsplit), cur[crange].second);
                            answer_t::iterator loc = cur.erase(cur.begin()+crange);
                            cur.insert(loc, R);
                            cur.insert(loc, L);
                            //add it to the results
                            results.push_back(cur);
                        }
                    }
                }
            }
            return results;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-29
          • 1970-01-01
          • 2018-10-26
          • 1970-01-01
          相关资源
          最近更新 更多