spoj混合物:需要有关逻辑的帮助

时间:2020-06-13 08:06:34

标签: algorithm dynamic-programming

该问题要求将产生的烟雾最小化。

我的方法: 因为在任何时刻,仅会拾取相邻的混合物。所以我尝试使用dp。就像我知道n-1种混合物的答案一样,我可以获得n种混合物的答案。

如何?: 第n种混合物将是

情况1:与第(n-1)种混合物混合,并将其结果与第一种n-2种混合物的所得混合物混合。或

情况2:将混合的n-1个混合物混合在一起。

让dp [i]表示第一个i混合物的最小烟雾,而res [i]表示第一个i混合物的最终混合物。它们将包含课程的优化值。 A [i]表示第i种混合物的颜色

如此

案例1:dp [i] = dp [i-2] + A [i-1] A [i] + res [i-2] (A [i-1] + A [i])%100; 并且res ​​[i] =(res [i-2] + A [i] + A [i-1])%100;

对于情况2的

:dp [i] = dp [i-1] + res [i-1] * A [i]; 和res [i] =(res [i-1] + A [i])%100;

基本案例:

如果只有1种混合物的烟雾为0,则所得混合物本身就是混合物。 并且如果仅给定2种混合物的烟气= A [0] * A [1]且产量=(A [0] + A [1])%100

我的代码:在4个案例中,它仅通过了1个(不是示例测试案例) 我的逻辑错在哪里?

问题陈述

哈利·波特(Harry Potter)在他面前有n种混合物,排成一排。每个混合物都有100种不同的颜色之一(颜色的数字从0到99)。

他想将所有这些混合物混合在一起。在每个步骤中,他将采用两种彼此相邻的混合物并将它们混合在一起,然后将所得混合物放在适当的位置。

将两种颜色的a和b的混合物混合时,所得混合物的颜色将为(a + b)mod 100。

此外,在此过程中还会冒烟。混合颜色a和b的两种混合物时产生的烟雾量为a * b。

找出将所有混合物混合在一起时,哈利能获得的最低烟雾量是什么。

输入 输入中将包含许多测试用例。

每个测试用例的第一行将包含n(混合数)1 <= n <= 100。

第二行将包含介于0到99之间的n个整数-混合物的初始颜色。

输出 对于每个测试用例,输出最少的烟雾。

示例

输入:

2
18 19
3
40 60 20

输出:

342
2400
 #include<bits/stdc++.h>
    using namespace std;
    int main() {
        int n;
        cin>>n; //no. of mixtures
        int A[n];
        for(int i=0;i<n;i++)
            cin>>A[i]; // filling their values.
        if(n==1)  //base case
        {
            cout<<0<<endl;
            return 0;
        }
        long long dp[n],res[n];
        dp[0]=0;                     // for 2 mixtures
        res[0]=A[0];
        dp[1]=A[1]*A[0];
        res[1]=(A[1]+A[0])%100;     //
        for(int i=2;i<n;i++)        
        {
            long long ans1,ans2,res1,res2;

            ans1=dp[i-1]+res[i-1]*A[i];
            res1=(res[i-1]+A[i])%100;

        ans2=dp[i-2]+A[i-1]*A[i]+res[i-2]*((A[i-1]+A[i])%100);
            res2=(res[i-2]+(A[i-1]+A[i])%100)%100;

            dp[i]=min(ans1,ans2);
            if(dp[i]==ans1)
                res[i]=res1;
            else
                res[i]=res2;    
        }
        cout<<dp[n-1];
        return 0;
    }

1 个答案:

答案 0 :(得分:0)

您的代码输出6500作为输入20 10 30 30 40,但正确的结果是3500:

20  10  30  30  40
200/30  900/60
  30      60    40
          2400/0
  30      0

smoke = 200 + 900 + 2400 = 3500

一个诀窍是要意识到(或得知)任何折叠间隔的最终颜色都是相同的,而不管其混合顺序如何。下面的采用分而治之的Python代码已被接受。

我们可以使用两种想法:(1)由于加法的关联性,我们选择通过混合将所有方式折叠到一个元素的任何特定间隔都将产生相同的颜色,而不管混合的顺序如何;以及(2 )给出任意间隔(尤其是完整列表)的最佳混合顺序,因为混合是在相邻颜色之间进行的,因此该间隔的最后混合必须有一些最佳单个位置,换句话说,是一个将整个部分分开的最佳位置间隔成两部分,以便在最终混合之前使每一侧完全塌陷。

基于这两个想法,我们基本上建立了一种“强力”重复效果-尝试每个可能的分割,并知道每个部分的颜色都不是我们需要的一种可能性以上的尺寸,然后执行这两个部分的重复率相同。希望代码中的基本情况很清楚。

import sys

# Returns (smoke, colour)
def f(lst, i, j, memo):
  # Empty interval
  if i > j:
    return (float('inf'), 0)

  # Single element
  if i == j:
    return (0, lst[i])

  if (i, j) in memo:
    return memo[(i, j)]

  best = (float('inf'), -1)

  for k in xrange(i, j):
    smoke_l, colour_l = f(lst, i, k, memo)
    smoke_r, colour_r = f(lst, k + 1, j, memo)
    smoke = smoke_l + smoke_r + colour_l * colour_r
    colour = (colour_l + colour_r) % 100
    best = min(best, (smoke, colour))

  memo[(i, j)] = best
  return best


# I/O
while True:
  line = sys.stdin.readline()
  if line:
    n = int(line)
    if n == 0:
      continue
    lst = sys.stdin.readline()
    lst = map(int, lst.split())
    print f(lst, 0, n-1, {})[0]
  else:
    break
相关问题