阿政0506 发表于 2023-7-21 18:01

研究生的算法题。了解一下?

今天刷到一个的算法题,感觉很有意思,但无奈才疏学浅,除了穷举想不到时间复杂度更低的方式。各位大手子们有没有思路可以指点一波。
如下:
现在有51个大小不同数值的数据(整数),现需要将它分为6组,每组的数据大致8-9个(如3组8个数据和3组9个数据),然后算出每组数据的平均值的方差,如何得到方差最小的组合?

wystudio 发表于 2023-7-21 19:17

这51个数有大小限制吗

木人头 发表于 2023-7-21 19:42

这是一个NP-hard问题,即不可再分割问题的一种。

leonrein 发表于 2023-7-21 20:16

Kmeans 聚类

blfiag 发表于 2023-7-21 21:45

需要聚成6个类
首先排序后得到xi(i=1, ... , 51)。
取x1和x(-1)分别为C1和C6的成员。
然后搜索剩余点,距离C1和C6中心最大距离之和的点xk,设置为Ck
剩余点依次类推,大体能定出其中5个类的元素及中心。
第6个类只能从相邻两类依次求和,找出最大距离那个数作为第6类。
剩余的数值逐一或打乱次序对号入座,不断更新类中心。

无法证明是最优,应该能混个次优?

sai609 发表于 2023-7-21 22:19

woe,iv,手动调整分箱数量,

dbns 发表于 2023-7-21 23:18

真高级,学习一下

xiaozhang0372 发表于 2023-7-22 13:52

你描述的问题属于经典的聚类问题,其中要将51个数据点分为6个组,每组包含的数据点数量大致相等,并且需要找到一种分组方案,使得每组数据的平均值的方差最小化。

通常采用启发式算法来近似求解,使用以下4个步骤
1.初始化:随机选择6个数据点作为6个组的中心点。
2.分配阶段:将其余的数据点分配到距离其最近的中心点所代表的组中。
3.更新阶段:计算每个组的平均值,并将该组的中心点更新为计算得到的平均值。
4.重复步骤2和步骤3,直到分组不再发生变化或达到最大迭代次数为止。
一般来说,随着迭代的进行,组内的数据点会趋于更加相似,使得方差逐渐减小。然而,由于问题的NP-hard性质,这个方法不能保证找到全局最优解,而只是寻找一个较好的近似解。

K-means算法的时间复杂度在实际应用中是可以接受的。不过,如果数据量非常大,或者数据维度较高,可能会导致算法的运行时间较长
优化措施:
1.初始中心点的选择:选择更好的初始中心点可能会使算法收敛更快。可以考虑使用K-means++等方法来选择更合适的初始中心点。
2.提前停止:在迭代过程中,可以设置一个收敛条件,例如当组内数据点的变化小于某个阈值时,提前停止迭代,避免不必要的计算。
3.并行计算:对于大规模数据集,可以考虑使用并行计算来加速距离计算和组内平均值的计算过程。
4.减少数据维度:如果数据维度很高,可以考虑使用降维技术(如主成分分析PCA)来减少数据的维度,从而加快算法运行速度。
5.Mini-batch K-means:对于非常大的数据集,可以考虑使用Mini-batch K-means算法,在每次迭代中只随机选择一部分数据点来更新中心点,达到加速算法运行的目的。

Hetwen 发表于 2023-7-23 20:54

首先,我们可以将问题转化为一个多维背包问题。每个数据对应一个物品,每组对应一个背包,背包的容量为8或9(根据要求)。

假设dp表示将前i个数据分到前j个背包中的最小方差,则有以下状态转移方程:

```python
dp = min(dp, dp + variance(k+1, i))
```
其中k表示第j个背包中的数据个数(8或9),variance(k+1, i)表示将第k+1个数据到第i个数据分到第j个背包中后的方差。

具体实现时,可以使用一个二维数组dp来保存中间结果。首先将dp初始化为一个较大的值,然后逐步计算得到最小方差。

最后,通过回溯找出具体的分组方案。

以下是一个简化的示例代码,供你参考:

```python

import numpy as np

def divide_groups(data):
    n = len(data)
    m = 6# 分组数
    k = # 每组数据个数

    # 计算方差
    def variance(start, end):
      return np.var(data)

    # 初始化dp数组
    dp = np.zeros((n+1, m+1))
    dp = float('inf')

    # 动态规划计算最小方差
    for i in range(1, n+1):
      for j in range(1, m+1):
            for x in range(k, i+1):
                dp = min(dp, dp] + variance(x, i))

    # 回溯得到分组方案
    groups = [[] for _ in range(m)]
    i = n
    for j in range(m, 0, -1):
      for x in range(i, k-1, -1):
            if abs(dp - (dp] + variance(x, i))) < 1e-6:
                groups = data
                i = x - 1
                break

    return groups

# 测试
data =
groups = divide_groups(data)
for i, group in enumerate(groups):
    print(f"Group {i+1}: {group}")

```

阿政0506 发表于 2023-7-24 10:47

wystudio 发表于 2023-7-21 19:17
这51个数有大小限制吗

没有,可以理解为随机生成51个整数
页: [1]
查看完整版本: 研究生的算法题。了解一下?