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

时间:2013-08-30 00:46:56

标签: java c++ c algorithm

我正在寻找随机的TopCoder问题,以便在比赛期间尝试改进,我今天遇到过一个我想要一些输入的问题。

问题陈述

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

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

Teddy和Tracy希望购买一些鲜花并将它们排成矩形网格。该网格必须布置成使得每个单元格恰好包含一个花朵,并且共享边缘的任何两个单元格必须包含不同种类的花朵。此外,Teddy和Tracy必须使用他们购买的所有鲜花。

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.

到目前为止我的想法

所以到目前为止我对这个问题有过一些想法,以至于我觉得解决这个问题可能很重要。随意忽视它们。

  • 由花朵创造的每个矩形在周边都会有偶数的玫瑰和百合花。因此,你可以通过花两个中较小的一个来找到你可以用鲜花制作的最大的矩形,比如你有6朵玫瑰和4朵百合花,因为你只有4个百合花,你可以制作的最大尺寸矩形包括4个玫瑰和4朵百合花。

  • 当您考虑矩形的每个单元格必须用花朵填充时,显然会出现挑战,因此您必须找到“最适合”的矩形,只要满足您的花朵数量,就能满足两者:为剩下的花朵提供足够的“中间”细胞,并尽可能靠近正方形。

我已经查看了一些发布的解决方案,但是代码往往非常混淆和优化(在快速编写方面),因此很难提取作者为解决方案考虑的概念。

我很感激任何想法,我很想学习一些方法来快速解决这样的问题。

3 个答案:

答案 0 :(得分:0)

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

回答这个问题应该让你解决问题。

答案 1 :(得分:0)

查看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 + rosesnum 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

答案 2 :(得分:0)

当谈到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 |。

请询问您是否还有其他问题。