【问题标题】:Calculating total number of mismatched socks combinations计算不匹配袜子组合的总数
【发布时间】:2018-04-13 07:18:49
【问题描述】:

这是 2015 年 ICPC 西北编程竞赛的问题之一,我想知道是否有更简单或更有效的方法。

问题来了:

“弗雷德喜欢穿不匹配的袜子。这有时意味着他必须提前计划。 假设他的袜子抽屉里有一只红色、一只蓝色和两只绿色的袜子。如果他穿着 红色配蓝色,他一直穿着相配的绿色袜子。他把两个放在一起 如果他将红色与绿色配对,然后将蓝色与绿色配对,则配对不匹配。鉴于 他袜子抽屉里的东西,他能放多少双不匹配的袜子?”

这是一个示例输入:

Color 1 -> 4 socks

Color 2 -> 3 socks

Color 3 -> 7 socks

Color 4 -> 11 socks

Color 5 -> 4 socks

我的做法是首先将输入读入一个数组并逐步对其进行排序。这样,我将在数组末尾拥有最多数量的袜子。从这里我基本上比较arr[i]arr[i-1] 并得到它们之间的最小值。将其添加到总数中,保存剩余部分,然后重复沿数组向下的过程。例如,使用示例输入,它看起来像这样:

排序后的数组:[3,4,4,7,11]

1:3 socks---> 1:3 socks---> 1:0 socks---> 1:0 socks

2:4 socks---> 2:4 socks---> 2:1 socks---> 2:1 socks

3:4 socks---> 3:4 socks---> 3:0 socks---> 3:0 socks

4:7 socks---> 4:0 socks---> 4:0 socks---> 4:0 socks

5:11 socks---> 5:4 socks---> 5:0 socks---> 5:0 socks

------> 总共 = 14 种可能的不匹配袜子组合。这似乎太天真了。有人对如何优化它有任何想法吗?如有必要,我可以发布我的代码。

【问题讨论】:

  • 我认为这种方法不正确,因为您没有从最高计数中减去最低计数。考虑1, 20, 80, 81 - 在第一次迭代之后你会得到1, 20, 0, 1 并且无法对 20 做很多事情,并得到答案 82 剩下 18 只袜子(正确答案应该是 91 没有剩下袜子)。
  • @Brendan,这是不正确的。在您给出的示例中,答案是 82,其余 18 只袜子的颜色都相同,因此它们不计入总数的一部分。还是我理解错了?
  • 哦。我的方法也不对。为了正确答案;第一次迭代后可能是0, 20, 80, 80,第二次迭代后可能是0, 10, 70, 80,第三次迭代后可能是0, 0, 70, 70

标签: algorithm optimization combinatorics


【解决方案1】:

我认为可以通过将所有可能的不同袜子颜色分组检查成 2 堆来找到最佳解决方案。对于每个这样的分组p,可以制作奇数双袜子,其中p 是最小堆中袜子的数量。您想要给出最大p 的分组。您可以递归地将所有可能的袜子分组生成 2 堆。

这里有一些 Java 代码来说明:

public static void main(String[] args)
{
    int[] socks = {3,4,4,7,11};
    System.out.println(count(0, 0, socks, 0));
}

static int count(int a, int b, int[] socks, int i)
{
    if(i == socks.length)
    {
        return Math.min(a, b);
    }

    return Math.max(count(a+socks[i], b,          socks, i+1), 
                    count(a,          b+socks[i], socks, i+1));
}

输出:

14

【讨论】:

  • 这看起来很可靠,我稍后会更详细地查看它并尝试实现它。
  • 对此我很抱歉;但它也遇到了与我的方法(和原始方法)相同的问题。我想我们发现了为什么挑战似乎有点太容易了......
【解决方案2】:

构建图数据结构。每只袜子都是顶点。从每个顶点到另一种颜色的所有顶点制作边。

现在找到maximum matching 的幂 - 没有公共顶点的边集的大小。

您可以在多项式时间 O(V^2*E) 内使用 Edmonds algorithm 构建最大匹配。似乎该任务的图形会很密集,因此复杂度趋于 O(V^4)。还有复杂度较低的 Micali 和 Vazirani 算法(不知道实现难度)。

如果您的任务本身不需要最大匹配 - 仅需要边数,则可以使用基于 Tutte 矩阵定理的随机 Lovasz 算法计算该值。 (我没有找到简明的英文描述 - 可能术语可能会有所不同,俄语中的简短一个是here

【讨论】:

  • 这就是我想要的。谢谢,我会相应地调查并更新问题。
  • 我不相信这个答案有任何意义。该解决方案将涉及确实具有共同顶点的边(简单示例:“20 red, 30 blue, 50 green”,其中绿色袜子必须与红色袜子和蓝色袜子配对)。
【解决方案3】:

“希望这次能改正!”方法

第 1 步:检查是否还有 2 种或更多颜色。如果没有颜色或只剩下一种颜色,您就完成了(找不到更多配对)。

第 2 步:找到一种非零计数最少的颜色

第3步:排除计数最低的颜色(以防所有颜色的计数相同);找到最高计数并确定有多少颜色共享最高计数

第四步:排除计数最低的颜色和计数最高的所有颜色;尝试找到第二高的计数。

步骤 5a:如果计数第二高,则计算 amount_to_pair = min(highest_count - second_highest_count, lowest_count)

第 5b 步:如果没有第二高计数,则计算 amount_to_pair = lowest_count

第 6 步:创建amount_to_pair 配对,将计数最低的颜色的袜子与计数最高的颜色的袜子尽可能均匀地配对(例如,如果有 9 只红色袜子、20 只蓝色袜子和 20 只绿色袜子;然后创建 5 个“红蓝”对和 4 个“红绿”对)。

第 7 步:转到第 1 步。

例子(cmets中提到的病理案例):

初始条件

Color 1 -> 1 socks
Color 2 -> 20 socks
Color 3 -> 80 socks
Color 4 -> 81 socks

第一次迭代:

Color 1 -> 1 socks (lowest non-zero count)
Color 2 -> 20 socks
Color 3 -> 80 socks (2nd highest count)
Color 4 -> 81 socks (highest count)

Amount to remove = min(81-80, 1) = 1

Color 1 -> 1-1=0 socks (lowest non-zero count)
Color 2 -> 20 socks
Color 3 -> 80 socks
Color 4 -> 81-1=80 socks (highest count)

Results so far:
   (1 pair of colour 1 and colour 4)

第二次迭代:

Color 1 -> 0 socks
Color 2 -> 20 socks (lowest non-zero count)
Color 3 -> 80 socks (highest count)
Color 4 -> 80 socks (highest count)

Amount to remove = 20

Color 1 -> 0 socks
Color 2 -> 20-20=0 socks (lowest non-zero count)
Color 3 -> 80-(20/2)=70 socks (highest count)
Color 4 -> 80-(20-20/2)=70 socks (highest count)

Results so far:
   (1 of colour 1 and colour 4)
   (10 of colour 2 and colour 3)
   (10 of colour 2 and colour 4)

第三次迭代:

Color 1 -> 0 socks
Color 2 -> 0 socks
Color 3 -> 70 socks (lowest non-zero count)
Color 4 -> 70 socks (highest count)

Amount to remove = 70

Color 1 -> 0 socks
Color 2 -> 0 socks
Color 3 -> 70-70=0 socks (lowest non-zero count)
Color 4 -> 70-70=0 socks (highest count)

Results so far:
   (1 of colour 1 and colour 4)
   (10 of colour 2 and colour 3)
   (10 of colour 2 and colour 4)
   (70 of colour 3 and colour 4)

原始方法

警告:以下方法在各种病理情况下给出错误结果(并且已被上述算法更新/替换)。我把它留在这里是为了给一些 cmets 提供背景

起始条件:

Color 1 -> 4 socks
Color 2 -> 3 socks
Color 3 -> 7 socks
Color 4 -> 11 socks
Color 5 -> 4 socks

找到最高计数和最低计数;并取消计数最低的那个,使其不复存在:

Color 1 -> 4 socks
Color 3 -> 7 socks
Color 4 -> 11-3=8 socks
Color 5 -> 4 socks

Results so far:
   (3 of colour 2 and colour 4)

再做一次:

Color 3 -> 7 socks
Color 4 -> 8-4=4 socks
Color 5 -> 4 socks

Results so far:
   (3 of colour 2 and colour 4)
   (4 of colour 1 and colour 4)

再做一次:

Color 3 -> 7-4=3 socks
Color 5 -> 4 socks

Results so far:
   (3 of colour 2 and colour 4)
   (4 of colour 1 and colour 4)
   (4 of colour 4 and colour 3)

再做一次:

Color 5 -> 4-3=1 sock

Results so far:
   (3 of colour 2 and colour 4)
   (4 of colour 1 and colour 4)
   (4 of colour 4 and colour 3)
   (4 of colour 3 and colour 5)

停下来,因为只剩下一种颜色了。

【讨论】:

  • 这与我所做的非常相似,因为您仍在比较它们并获得差异。对我来说,这似乎很幼稚。我想知道除了浏览列表并比较所有内容之外是否还有其他方法
  • @Acuriousone:主要区别在于我使用了一个未排序的列表(避免了最初对其进行排序并修复每次迭代的顺序的开销,但每次迭代都会增加“搜索和压缩”的开销) .这应该比原来的性能略好(启动开销更少,但每次迭代的开销相似)。
  • @Acuriousone:请注意,每次迭代都必须从计数最高的颜色中减去(如果不这样做会导致错误答案);每次迭代,计数最高的颜色都会发生变化(因为你从中减去了)。这意味着不可能避免每次迭代都遍历列表(无论是修复顺序,还是找到新的最高值)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 1970-01-01
  • 2015-11-06
  • 1970-01-01
  • 2018-09-17
相关资源
最近更新 更多