【问题标题】:spoj Mixtures : Need help regarding logicspoj Mixtures : 需要关于逻辑的帮助
【发布时间】:2020-06-13 08:06:34
【问题描述】:

问题要求尽量减少产生的烟雾。

我的方法: 因为在任何时刻,只会拾取相邻的混合物。所以我尝试使用 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 个(不是示例测试用例) 我的逻辑哪里错了?

问题陈述

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

他想将所有这些混合物混合在一起。在每一步,他都会取两种并排放置的混合物并将它们混合在一起,然后将得到的混合物放在原位。

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

另外,在这个过程中会有一些烟雾。混合两种颜色a和b时产生的烟雾量为a*b。

找出当把所有混合物混合在一起时哈利能得到的最小烟雾量是多少。

输入 输入中会有很多测试用例。

每个测试用例的第一行将包含 n,混合数,1

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

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

示例

输入:

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

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:

    您的代码输出 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
    

    【讨论】:

    • 你能详细解释一下这个方法吗?
    • @chaitanya_12789 当然,我在答案中添加了更多信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    • 2014-07-08
    • 1970-01-01
    相关资源
    最近更新 更多