【问题标题】:Substituting redundant subsets替换冗余子集
【发布时间】:2015-07-11 18:26:13
【问题描述】:

我给出了一组包含两个元素的元组(它们按第二个元素排序):

{
{(1,"c1"), (1,"c2"), (1,"c3"), (1,"c5")}
{(1,"c1"), (2,"c3"), (1,"c5")},
{(1,"c1"), (1,"c3"), (1,"c5")},
}

任务是替换元素的冗余子集。给定一个数字 k >= 1。用至少 k 个元素替换所有子集,这些元素在样本集中出现多次。替换序列应尽可能大。 简化形式:

{
{z, (1,"c2")}
{(1,"c1"), (2,"c3"), (1,"c5")},
{z},
}
z := {(1,"c1"), (1,"c3"), (1,"c5")}

我的原生方法是, 从第一组开始,然后为每组计算他们有多少匹配。然后选择匹配最多的那个并替换。然后重新开始这个过程,直到没有其他集合有超过 k 个匹配。然后移动到下一组并做同样的事情,您可以忽略之前的所有组。

只有当两个值匹配时元素才相等。第二个值是一个字符串,但首先用数字替换它们可能会更好。第一个是浮点数。

这在我看来很像数据压缩。有没有更有效的算法来计算这个?有没有为此目的的良好数据结构?

【问题讨论】:

  • 第二个 sn-p 的第二行有错字吗?它应该是:{z, (1,"c2")} 吗?此外,这似乎类似于longest repeated sub-sequence problem
  • 是的,修复了它,是的,这看起来像我要找的东西
  • 您描述的技术,您需要从一组中挑选每个可能的序列并将其与其他组进行比较。这似乎是 O(n!xm) 时间复杂度。其中 n 是平均集合大小,m 是集合数。这很快就会失控。您的问题比 wiki 问题稍微复杂一些,因为您的子字符串不必连续才能匹配(例如 line2 中的额外 c2 仍然是匹配项)。如果你仍然能以某种方式解决这个问题,O(nxm) 将是一个很大的改进。
  • 刚刚看到你的另一个问题:stackoverflow.com/questions/29996166/… 这个问题似乎是那个问题的续集,例如,它正在使用正则表达式吐出的输出?只是为了确保我们不会追逐 XY problem,您能否描述一下您实际上想要对这些操作进行哪些操作?
  • 该文件由线性方程组成。在我读完所有方程后,我需要检测出现在许多方程中的冗余部分,并将它们作为新方程插入,将它们设置为等于替换变量,然后将其插入原始位置。系统将变得更大,但更稀疏,因为每一行包含的条目更少。

标签: c++ performance algorithm data-structures


【解决方案1】:

您可以为此使用maps

set of sets of tuples 视为set of maps,现在问题变成'z' map 是否是each map 的子集,如果是子集,我们需要将map 'z' 输出为z 并将map 的其余元素输出为pairs,如果没有,我们只需输出map

现在,要查找它是否为 map is subset of another map ,我们使用 STL 函数:

Includes

包括测试一个排序范围是否包含另一个排序范围。也就是说,当且仅当对于 [first2, last2) 中的每个元素,在 [first1, last1) [2] 中也存在等效元素 [1] 时,它才返回 true。 [first1, last1) 和 [first2, last2) 都必须按升序排序。

include 的两个版本在定义一个元素是否小于另一个元素的方式上有所不同。第一个版本使用 operator

这是打印map is subset的程序,根据你的要求修改它,你可以自己尝试输出程序(as it is easy one):

#include <algorithm>
#include <iostream>
#include <map>

int main()
{
    std::map<int, std::string> a,b;
    

    a[0] = "0";
    a[1] = "1";
    b[0] = "0";

    std::cout << "b ⊆ a? " << std::includes(a.begin(), a.end(), b.begin(), b.end()) << " (will be 1)\n";

    b[1] = "1";
    std::cout << "b ⊆ a? " << std::includes(a.begin(), a.end(), b.begin(), b.end()) << " (will be 1)\n";

    b[2] = "2";
    std::cout << "b ⊆ a? " << std::includes(a.begin(), a.end(), b.begin(), b.end()) << " (will be 0)\n";
}

【讨论】:

    【解决方案2】:

    如果您的线性方程中的变量数量少于方程数量,您可以使用这种替代方法更快地计算出最大替换:

    问题陈述

    我们已经在 cmets 中澄清 z := (1,"c3") 可以部分替换 {2,"c3"}{z,(1,"c3") 鉴于此,数据点是元组的事实与这个问题无关关注 - 允许我将您的意见视为:

      {c1, c2, c3, c5}
      {c1, c3, c5}
      {c1, c3, c5}
    

    接下来的问题是找到最大的集合 {ca,cb..},它是至少 2 个输入集的子集。

    输入集可以表示为

         | c1 | c2 | c3 | c5 |
    +----|----|----|----|----|
    | S1 | 1  | 1  | 1  | 1  |
    | S2 | 1  | 0  | 1  | 1  |
    | S3 | 1  | 0  | 1  | 1  |
    

    解决方案

    解决方案 A 的形式为

         | c1 | c2 | c3 | c5 | subset of |
    +----|----|----|----|----|-----------|
    | A  | 1  | 1  | 1  | 1  | k         |
    

    其中 k 是 A 所属的输入集的数量,需要大于 2。现在对于 cx 的 n 个值,A 有 2^n 种可能性。评估候选解 Ax 是否是集合 Sx 的子集,涉及位域 Ax 与位域 Sx 的按位与运算,然后对结果的各个位进行与运算。

    遍历 Ax 的可能值,从设置的大多数位开始,第一个 k>1 的 A 值是所需的解决方案。

    | s  | c1 | c2 | c3 | c5 | subset of |
    |----|----|----|----|----|-----------|
    | A1 | 1  | 1  | 1  | 1  | 1         |
    | A2 | 1  | 1  | 1  | 0  | 0         |
    | A3 | 1  | 1  | 0  | 1  | 0         |
    | A4 | 1  | 0  | 1  | 1  | 3 <-bingo!|
    | A5 | 0  | 1  | 1  | 1  |           |
    | A6 | 1  | 1  | 0  | 0  |           |
    | A7 | 0  | 1  | 1  | 0  |           |
    | A  ...                             |
    

    复杂性

    这个解决方案的时间复杂度仍然是指数级的。但是,它以指数方式依赖于 cx 的值的数量。与输入集数量呈指数增长的朴素解决方案相反。如果变量数(cx)小于输入集数(Sx),这种方法会更快。

    注意:如果此解决方案顶部关于(2,"c3") 的假设不正确,那么您只需将(2,"c3") 视为单独的cx 值。输入变为:

    {c1, c2, c3, c5}
    {c1, c6, c5}
    {c1, c3, c5}
    

    这个答案的其余部分仍然有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 2020-01-18
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多