Java SRM 489 DIV 2(500 pt)的TopCoder最优选择算法

Java SRM 489 DIV 2(500 pt)的TopCoder最优选择算法,java,c++,c,algorithm,Java,C++,C,Algorithm,我正在研究随机TopCoder问题,以便在比赛中尝试改进,今天我遇到了一个问题,我想了解一下 问题陈述 泰迪喜欢玫瑰,特蕾西喜欢百合花。他们想把这些花种在一个大花园里 然而,镇上唯一的花店以玫瑰和百合为代表,以小包的形式出售这些花。第i包里有玫瑰和百合花。每包只能买一次 特迪和特蕾西想买些花,把它们排列成长方形网格。该网格的排列方式必须确保每个单元格正好包含一朵花,共享一条边的任何两个单元格必须包含不同种类的花。此外,特迪和特蕾西必须使用他们购买的所有鲜花 特迪和特蕾西喜欢方形网格,所以他们想买

我正在研究随机TopCoder问题,以便在比赛中尝试改进,今天我遇到了一个问题,我想了解一下

问题陈述

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

然而,镇上唯一的花店以玫瑰和百合为代表,以小包的形式出售这些花。第i包里有玫瑰和百合花。每包只能买一次

特迪和特蕾西想买些花,把它们排列成长方形网格。该网格的排列方式必须确保每个单元格正好包含一朵花,共享一条边的任何两个单元格必须包含不同种类的花。此外,特迪和特蕾西必须使用他们购买的所有鲜花

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

定义

班级:百花

方法:购买

参数:向量,向量

返回:int

方法签名:int buyvector玫瑰、vector百合

范例

{2,4} {4,2}

回报:1

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

RLRL LR RLRL

这种排列的高度和宽度之差为1

到目前为止我的想法

到目前为止,我对这个问题有一些想法,我认为这对解决这个问题很重要。不要理会他们

每一个由花朵组成的长方形的周边都会有偶数的玫瑰和百合花。因此,如果你有6朵玫瑰和4朵百合花,那么你可以用这些花做成最大的长方形,如果你有6朵玫瑰和4朵百合花,那么你能做成的最大长方形包括4朵玫瑰和4朵百合花

当你认为长方形的每一个细胞都必须装满一朵花时,这个挑战就显而易见了,所以你必须找到最适合的矩形,考虑到你所拥有的花的数量,这两个都可以满足:为其余的花朵提供足够的中间细胞,并尽可能地接近正方形。p> 我已经看过一些发布的解决方案,但是代码在快速编写方面往往非常模糊和优化,因此很难提取作者在解决方案中的概念


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

思考以下问题:在矩阵N*M中,我可以放置超过一半的矩阵百合/玫瑰吗


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

看看上面的例子,看起来只有两种可能性:

|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
}

谈到TopCoder,问题陈述中最重要的部分之一是约束部分,因为这通常说明在时间限制内什么是可能的,什么不是

在您的情况下,有atmost 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
   }
}
一旦给了你一组数据包,你能告诉我你能把一个矩形做成多大吗

提示:当你们把一朵百合花固定在左上角时,你们怎么安排剩下的花呢? 附言:只有一条路。 类似地,在左上角固定玫瑰时,只有一种方法可以填充矩形

一旦你学会了这一点,只需迭代所有子集的组合,看看哪一个会产生最小的| R-C |


如果您还有更多问题,请询问。

对数据包的数量有哪些限制?@IVlad-玫瑰和百合将包含相同数量的元素,包括1到16个元素-玫瑰和百合花的每种成分都在0到10000之间,包括0到10000-玫瑰和百合代表的每个包中的花朵总数将大于0。我不确定是否遵循此提示。对于某些矩阵,例如7x7,超过一半的花位于m
Idle 25/49,对于其他的,比如6x6的花,少于一半的花将在中间16/36。我没有问中间有多少,但是在矩阵中的任何点上有多少个LILLY。如果你看它,你会发现它的行为就像一个棋盘。对于奇数的百合花或玫瑰,你最多有一半+1。我不明白为什么只有一种方法来排列花。例如,如果您有一个包含6朵玫瑰和6朵百合花的子集,您可以将它们排列为3x4 LRLR RLRL LR LR,或者您可以将它们排列为1x12 LRLR LR。似乎有必要构造每个子集可能形成的矩形,然后保存最接近正方形的矩形。但简单的解决方案并不意味着他们做了类似的事情。谢谢你的帮助。提示:你真的需要所有可能的矩形来组合数据包吗?实际上|玫瑰数-莉莉数|==1,对于任何行数和列数为奇数的矩形网格
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
   }
}