TopCoder 最佳选择算法来自 SRM 489 DIV 2 (500 pt)

Posted

技术标签:

【中文标题】TopCoder 最佳选择算法来自 SRM 489 DIV 2 (500 pt)【英文标题】:TopCoder optimal choice algorithm from SRM 489 DIV 2 (500 pt) 【发布时间】:2013-08-30 00:46:55 【问题描述】:

我正在查看随机的 TopCoder 问题,以便在比赛中尝试和改进,我今天遇到了一个我想提供一些意见的问题。

问题陈述 

泰迪喜欢玫瑰,特蕾西喜欢百合花。他们希望将这些花种在一个大花园里。

然而,镇上唯一的花店以vector<int>s 玫瑰和百合为代表的小包出售这些鲜花。第 i 个数据包包含 roses[i] 玫瑰和 lilies[i] 百合。每包只能购买一次。

泰迪和特蕾西想买一些花,把它们排列成一个矩形网格。这个网格的排列必须使每个单元格只包含一朵花,并且任何两个共享边的单元格必须包含不同种类的花。此外,泰迪和特蕾西必须使用他们购买的所有鲜花。

Teddy 和 Tracy 喜欢方形网格,所以他们想买一套小包,这样他们就可以将花朵排列成最方形的网格。更准确地说,他们希望将花朵排列成 R x C 网格,其中 R 和 C 是正整数,使得 |R-C| (|R-C| 表示 R-C 的绝对值)被最小化。返回此最小绝对值,如果不存在有效排列,则返回 -1。

定义

班级:BuyingFlowers

方法:buy

参数:vector <int>, vector <int>

返回:int

方法签名:int buy(vector <int> roses, vector <int> lilies)

示例

2, 4 4、2

返回:1

购买所有包获得 6 朵玫瑰和 6 朵百合花,他们可以创建一个 3 x 4 的网格,排列如下:

RLRL LRLR RLRL

这种排列的高宽差为1。

到目前为止我的想法

到目前为止,我对这个问题有几个想法,我认为这可能对解决它很重要。随意忽略它们。

由花朵创建的每个矩形的周边都会有偶数朵玫瑰和百合花。所以你可以用花做的最大矩形可以通过取两者中较小的一个来找到玫瑰和 4 朵百合花。

当您考虑到矩形的每个单元格都必须用一朵花填充时,挑战显然就来了,因此您必须找到“最合适”的矩形,给定您拥有的花数量,满足两者:为其余的花提供足够的“中间”单元,并尽可能靠近正方形。

我查看了一些发布的解决方案,但是代码往往非常模糊和优化(就快速编写而言),因此很难提取作者对解决方案的想法.

如果有任何想法,我将不胜感激,我很想了解一些快速解决此类问题的方法。

【问题讨论】:

包数有什么限制? @IVlad - 玫瑰和百合将包含相同数量的元素,介于 1 和 16 之间,包括 1 和 16。 - 玫瑰和百合的每个元素将在 0 到 10000 之间,包括在内。 - 以玫瑰和百合为代表的每包鲜花总数将大于0。 【参考方案1】:

对于 TopCoder,问题陈述中最重要的部分之一是约束部分,因为它通常规定在时间限制内什么是可能的,什么是不可能的。

在您的情况下,最多有 16 个数据包。由于可能的子集总数 =2^16=65536 非常低,我们可以查看所有数据包子集并决定哪个产生最佳组合。

为此使用位操作(在 C++ 中)

for(int i=0;i<(1<<16);i++)

 //i represents a subset
 for(int j=0;j<16;j++)
   if(i & (1<<j))
   
    //j-th packet is present in subset
   

给你一个组合包后,你能说出你能做出多大的矩形吗?

是的。

提示:当你在左上角固定一朵百合花时,你如何安排剩余的花朵?P.S:只有一种方法。 同样,当您在左上角固定一朵玫瑰时,只有一种方法可以填充矩形。

一旦你选择了这个,只需遍历所有子集组合,看看哪个产生最小 |R-C|。

如果您还有其他问题,请询问。

【讨论】:

我不明白怎么只有一种方法来安排鲜花。例如,如果您有一个包含 6 朵玫瑰和 6 朵百合花的子集,您可以将它们排列成 3x4 LRLR RLRL LRLR 或者您可以将它们排列成 1x12 LRLRLRLRLRLRLR 似乎有必要构造每个可能的矩形形状,每个子集都可以组成然后保存最接近正方形的那个。但是简单的解决方案并不表明他们会做这样的事情。感谢您的帮助。 提示:你真的需要所有可能的矩形来组合数据包吗?【参考方案2】:

想想下面的问题:在一个矩阵 N * M 中,我可以放一半以上的百合花/玫瑰吗?

回答这个问题应该可以让你完成这个问题。

【讨论】:

我不确定我是否遵循了这个提示。对于某些矩阵,例如 7x7,超过一半的花朵位于中间 (25/49),而对于其他矩阵,例如 6x6,不到一半的花朵位于中间 (16/36)。 我没有问有多少在中间,而是在矩阵中的任何一点有多少百合。如果你看它,你会发现它的行为就像一个棋盘。你最多有一半(对于奇数个细胞,一半 + 1)百合或玫瑰。【参考方案3】:

看http://community.topcoder.com/stat?c=problem_statement&pm=11191的例子,貌似只有两种可能:

|number of roses - number of lillies| == 1, for odd R and odd C

or

number of roses == number of lillies, for even R or even C

如果这是真的,我会寻找一种方法来找到可以划分为最接近的两个整数因子(最好是平方根)的数字 lillies + roses(其中 num lillies == num roses|num roses - num lillies| == 1)。

在 TopCoder 示例中,我们有:

Example 0:     6 + 6 = 12, closest two factors 3x4
Example 1:     5 + 4 = 9, closest two factors 3x3

javascript 示例:

function closestFactors(n)

    var start = Math.floor(Math.sqrt(n))
    while (n % start != 0)
        start--
    return [start,n / start]


var roses = [1, 208, 19, 0, 3, 234, 1, 106, 99, 17],
    lillies = [58, 30, 3, 5, 0, 997, 9, 615, 77, 5]

function f(index, currentR, currentL, best)
 
    if (roses.length == index)
        return best
    for (var i = index; i < roses.length; i++) 
    
        var cr = currentR + roses[i],
            cl = currentL + lillies[i]
        if (cr == cl || Math.abs(cr - cl) == 1)
        
            var cf = closestFactors(cr + cl),
                current = Math.abs(cf[0] - cf[1])
            if (current == 0)
                return 0
            best = best < 0 ? current : Math.min(best,current)
        
        best = best < 0 ? f(i + 1, cr, cl, best)
                        : Math.min(best,f(i + 1, cr, cl, best))
        if (best == 0)
            return 0
    
    return best

控制台输出:

f(0,0,0,-1)
36

【讨论】:

其实|玫瑰的数量-莉莉的数量| == 1 对于行数和列数为奇数的任何矩形网格

以上是关于TopCoder 最佳选择算法来自 SRM 489 DIV 2 (500 pt)的主要内容,如果未能解决你的问题,请参考以下文章

Topcoder SRM 608 div1 题解

Topcoder SRM713 DFSCount

topcoder srm 450 div1

topcoder srm 580 div1

topcoder srm 600 div1

Topcoder SRM 603 div1题解