SPOJ 问题集(古典):9386。重新编曲 II #[MAIN112]

发布于 2024-12-02 16:40:07 字数 1139 浏览 1 评论 0原文

问题描述(为方便起见,在此处引用):

对于 N 个整数的序列,A1, A2, ..... AN

我们可以计算稳定因子P,为

P = 所有 (abs(Ai-Ai-1)*C[i]) 之和,其中 2 <= i <= N

C[i] 是将数字放在位置 i 的成本

您的任务是找到给定 N 个数字的最小 P,考虑到 它们的所有不同排列。


我只需要在正确的方向上推动,关于解决这个问题的一般方法。 (欢迎使用少量伪代码,但一旦总体算法大致清晰,我就有信心编写出一个解决方案)

我已经考虑了很长一段时间,但仍然坚持找到满足以下条件的解决方案:该问题的约束条件 (N <= 15) 暴力方法似乎只有在 N=10 时才表现良好。


首先,对于最大可能的测试用例 N=15,我不相信你能够枚举并考虑所有 15 个!排列以便在足够好的时间内找到答案,因为复杂性类别不允许这样做。

因此我们需要做出几个简化的假设来减少这个搜索空间。这就是我被困住的地方。或者也许这只是一种更聪明的方式来开始遍历这个排列空间?

我尝试使用动态编程来解决这个问题,因为排列共享许多公共位,可以在必要时预先计算(记忆)并存储和重用,例如。 A[] = 123456 & A[] = 123465 两者都会给出 1234- 相同的部分和,但这没有成功,因为你仍然需要经历 15!排列,并且在此之前会 TLE,所以它不好。

另一个想法是处理连续 A 和 C[] 的所有元素之间差异的所有可能排列,并首先找到将产生最小 abs(A[i]-A[j])*C[k ] 从所有这些中取出值,分配这些 &将它们标记为已使用,然后继续使用 i 或 j 中的一个来形成下一对,再次迭代并重复。这应该在多项式时间内完成(我猜测大约是 n^3),但对于某些示例,该假设失败。

我认为这个问题不应该那么困难,需要将其转换为某种图形问题 - 其中 A[i]、A[j] 形成节点,而 C[k] 是连接这些节点的边的成本,或者也许是一些布尔 SAT 问题……这一切似乎完全走上了错误的轨道。

如果您用 google 搜索此问题,除了托管此问题的 SPOJ 站点之外,您可能几乎找不到任何与此问题相关的内容。

非常感谢。

Problem description (quoted here for convenience):

For a sequence of N integers, A1, A2, ..... AN

We can calculate the stability factor P, as

P = sum of all (abs(Ai-Ai-1)*C[i]) where 2 <= i <= N

C[i] is the cost of putting a number at position i

Your task is find the minimum P for the given N numbers considering
all the different permutations of them.


I just need a nudge in the right direction, concerning the general approach to solving this problem. (Little bits of pseudocode are welcome, but I am confident to pretty much code up a solution once the overall algorithm is generally clear)

I've thought about this for quite a while, but am still stuck at arriving at any solution which satisfies the constraints of this problem (N <= 15) A brute-force approach only seems to perform well up to N=10 really.


First off, for the largest possible test case N=15, I don't believe that you're able to enumerate and consider all the 15! permutations in order to find your answer in sufficiently good time, as the complexity class will not permit this.

So we need to make several simplifying assumptions to reduce this search space. This is where I'm stuck. Or maybe it just comes down to a smarter way to begin traversing this permutation space?

I've tried to use dynamic programming to solve this problem, because permutations share many common bits which can be precomputed (memoised) and stored and reused when necessary, eg. A[] = 123456 & A[] = 123465 both will give the same partial sum for 1234-, but this yielded no success because you still have to go through the 15! permutations and will TLE way before that, so it's no good.

Another idea is to work with all the possible permutations of the differences between successive A's and all elements of C[], and first find the pair which will produce the minimum abs(A[i]-A[j])*C[k] value out of all these, assign those & mark them as used, then carry on with one of the i or j to form the next pair, iterate through again and repeat. This should complete in polynomial time (n^3 approx. i'm guessing), but the assumption fails for some examples.

I don't think this problem should be so difficult to involve transforming this into some sort of graph problem - where A[i], A[j] form nodes, and C[k] is the cost of the edge linking these nodes, or maybe some boolean SAT problem...that all seems to be going down the wrong track altogether.

If you were to google this, you'd probably find almost nothing related to this problem, apart from the SPOJ site hosting this problem.

Many thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

韶华倾负 2024-12-09 16:40:07

您可以对子集使用 O(n*2^n) 空间、O(n^2*n^2) 时间动态规划算法来求解。

关键的见解是,当您从左到右构建最佳解决方案时,只有先前放置的数字和使用的子集很重要,而不是事物在使用的子集中放置的顺序。

旅行推销员问题的解决方案具有基本相同的结构。

该计算 与您的 DP 想法走上正轨。我们的见解是,所有这些部分路径之后的最佳路径是相同的

1235

1325

2135

2315

3125

3215

因此,您实际上不需要探索所有可能的排列,只需探索那些具有最佳部分路径的排列即可。

下面是一些实现所描述算法的 TLE Python 代码,但由于 Python 中的常数因子减慢而失败。我转换为 C++ 并获得了 AC。

global A
global C

A = []
C = []

def Solve(used, last, cache):
  if (used, last) in cache:
      return cache[(used, last)]
  cur_pos = len(used)
  if cur_pos == len(A):
    return 0

  mn = 1e10
  for idx in range(len(A)):
      if not idx in used:
          next_used = used.union([idx])
          subcost = Solve(next_used, A[idx], cache)
          additional = C[cur_pos] * abs(last - A[idx])
          mn = min(mn, subcost + additional)
  cache[(used, last)] = mn
  return mn

T = int(raw_input())
for i in range(T):
  N = int(raw_input())
  A = map(int, raw_input().split())
  C = map(int, raw_input().split())
  cache = {}
  print min(Solve(frozenset([idx]), A[idx], cache) for idx in range(len(A)))

You can use an O(n*2^n) space, O(n^2*n^2) time dynamic programming algorithm on subsets to solve it.

The key insight is that as you are building up optimal solutions from left to right, only the previously placed number and the used subset matter, but not the order that things were placed in the used subset.

The computation has basically the same structure as this solution to the Travelling Salesman Problem.

You were on the right track with your DP idea. The insight is just that the optimal path after all of these partial paths is the same

1235

1325

2135

2315

3125

3215

So you don't actually need to explore all possible permutations, just those that having the best partial path.

Here is some TLE Python code that implements the algorithm described, but fails because of the constant factor slowdown in Python. I converted to C++ and got an AC.

global A
global C

A = []
C = []

def Solve(used, last, cache):
  if (used, last) in cache:
      return cache[(used, last)]
  cur_pos = len(used)
  if cur_pos == len(A):
    return 0

  mn = 1e10
  for idx in range(len(A)):
      if not idx in used:
          next_used = used.union([idx])
          subcost = Solve(next_used, A[idx], cache)
          additional = C[cur_pos] * abs(last - A[idx])
          mn = min(mn, subcost + additional)
  cache[(used, last)] = mn
  return mn

T = int(raw_input())
for i in range(T):
  N = int(raw_input())
  A = map(int, raw_input().split())
  C = map(int, raw_input().split())
  cache = {}
  print min(Solve(frozenset([idx]), A[idx], cache) for idx in range(len(A)))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文