Блог пользователя rr459595

Автор rr459595, история, 7 лет назад, По-английски

You are given a list of positive integers along with a sequence of operations from the set {∗,+}. You construct expressions from these two lists so that:

The numbers in the expression are drawn from the first list, without repetition and without altering their order. All the operators in the second list are used in the expression, in the same order. For example, if the two lists are [1,3,2,1,4] and [′∗′,′+′], the set of possible expressions you can form are 1∗3+2,1∗3+1,1∗3+4,1∗2+1,1∗2+4,...,2∗1+4 For each expression, the value is computed by bracketing operators from the right. That is, the expressions above are evaluated as 1∗(3+2),1∗(3+1),1∗(3+4),1∗(2+1),1∗(2+4),…,2∗(1+4). The aim is to determine maximum value among these expressions.In this example, the maximum value is 18, from the expression 3*2+4, which is evaluated as 3∗(2+4). You may assume that the length of the first list is more than the length of the second list.

How do I solve this problem ?

  • Проголосовать: нравится
  • -5
  • Проголосовать: не нравится

»
7 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Can someone at least give me some hint ?

  • »
    »
    7 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    An integer number in such arithmetic expression can be represented as a leaf node in a binary-tree representation of the expression. A binary operator '*' and '+' is a non-leaf node in such tree, and computing the value of the arithmetic expression is reduced to computing the value associated with the root node of its equivalent binary tree.

    Hope that helps.

    • »
      »
      »
      7 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      I understand the representation part. But how will binary tree help in choosing the right numbers to get maximum value?

      • »
        »
        »
        »
        7 лет назад, # ^ |
        Rev. 9   Проголосовать: нравится 0 Проголосовать: не нравится

        The binary tree should help in representing the arithmetic expression, not in choosing the right numbers. In your example, four candidate binary trees can be generated from the given ordered multi-set of binary operators A = {*,+}:

        E1 = B1+B2

        E2 = B1*B2

        E3 = B1*(B2+B3)

        E4 = (B1*B2)+B3

        Since the size of the ordered multi-set B = {1,3,2,1,4} is small, a brute-force algorithm should be sufficient to find the right choice of numbers within a reasonable execution time. Note that E1 is a sub-expression in E3, and that E2 is a sub-expression in E4. Therefore, it should be possible to generate the candidate binary trees and their equivalent arithmetic expressions iteratively. Also, since all numbers are strictly positive, the optimal solution exists in maximal length expressions.

        • »
          »
          »
          »
          »
          7 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          Set A = {*,+} is just an example. It could be {*,+,*,+,*} too (condition is that set should contains only *'s and +'s, that's it). Also I am interested in some method other than brute Force. Anyway, thanks for replying.

          • »
            »
            »
            »
            »
            »
            7 лет назад, # ^ |
            Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

            With pleasure, the iterative nature of generating the tree suggests that a dynamic programming approach may be possible, i.e. computing the value of larger expressions from smaller expressions.

          • »
            »
            »
            »
            »
            »
            7 лет назад, # ^ |
              Проголосовать: нравится +1 Проголосовать: не нравится

            you can do a 2D dp, where dp[i][j] is the largest value so far starting with ith element on list 1, using the j last operator in list 2.

            then dp[i-1][j] = max(dp[i][j] , applyOp(list2[k-j-1],list1[i-1], dp[i][j-1]);

            where k is size of list 2.

            • »
              »
              »
              »
              »
              »
              »
              7 лет назад, # ^ |
              Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

              Thank you. Got it !. What if we could use the operators in any order like if A = {*,+,*}, we can have A={*,*,+} or A={+,*,*} etc.. ?

              • »
                »
                »
                »
                »
                »
                »
                »
                7 лет назад, # ^ |
                  Проголосовать: нравится +1 Проголосовать: не нравится

                Not sure if there's better method, but the least u can do is a 3d dp, which is similar as above, but replace the operation dimension with 2 dimension, which is number of multiplication used and number of addition used.

»
7 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится

Given that the numbers are only positive and you only have the multiplication and addition operators you can devise a simple dynamic programming solution.

First, given that you do the bracketing from right to left, you can reverse your lits of numbers. Then, you can setup a look up table of size [Size of sequence of numbers] X [Size of sequence of operators]. The value of table[i][j] will indicate tha maximum value of the expression if you had only the first i numbers (last i before reversing the list) from the list and the first(last) j operators from the list of operators.

The value of table[i][j] is obtained by looking at the values of table[i-1][j-1] and table[i-1][j] denoting that you either add the next number in the list to the expression or you don't.

I think this should be enough of a hint. Do ask more questions if you are unsure how to set up the whole solution.

»
7 лет назад, # |
Rev. 25   Проголосовать: нравится +3 Проголосовать: не нравится

It may be possible to improve the computational efficiency of solving this problem by comparing the result of the two expressions (x*y) and (x+y) for a given pair of integer x and y. Suppose that f(x,y) = (x*y)-(x+y) = (x-1)*(y-1)-1.

It follows that f(x,y) >= 0, i.e. x*y >= x+y, when min(x,y) >= 2.

Let K, N and M be the size of the multi-set of binary operators, the size of the multi-set of integers and the number of ones in the latter set, respectively. Let L = K+1 be the number of integers in the optimal expression. It follows from the previous result that the optimal expression should have at most P = L-min(N-M,L) ones.

In your example, K = 2, N = 5, M = 2, L = 3, N-M = 3, and P = 0. It follows that the optimal expression should have no ones, i.e. composed of the numbers 3, 2, and 4 only.

Another possibility to improve the computational efficiency is to compute the histogram h(x) of the multi-set of integers, the number of times that x exists in the multi-set, and use it to compute g(x), the cumulative count of integers >= x in the multi-set. Any integer x whose g(x) < L should exist in the optimal expression.

Suppose that u is largest integer such that g(u) >= L, and that H = h(u). Then, u should be the smallest integer to exist in the optimal expression. Suppose also that v is the smallest integer to exist in the optimal solution such that g(v) < L, and that V = g(v). Then, the number of times that u should appear in the optimal solution is U=L-V, It is imperative that H >= U. The number of all possible ways to select U instances of u out of all H instances in the multi-set is C(H,U), where C(n,r) is the binomial coefficient.

The following is a C++17 code to compute the numbers that should exist in the optimal solution from the histogram h(x) function and the cumulative count function g(x)

#include <bits/stdc++.h>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    
    int H, K, L, M, N, U, V = 0, a, g = 0, u, v; string op; 
    
    cin >> K >> N >> op, L = K + 1; 
    
    map< int, vector< int > > h; set< pair< int, int > > exists; 
    
    for( int i = 0; i < N; i++ )
        cin >> a, h[ a ].push_back( i );
        
    auto it = h.crbegin(), iu = h.crend(), iv = it; M = h[ 1 ].size(); 
    
    while( iv != iu && ( V = g, g += iv->second.size() ) < L )
        iv++; 
    
    for( auto iw = it; iw != iv; v = iw->first, iw++ )
        for( auto i: iw->second )
            exists.emplace( i, iw->first );
    
    u = iv->first, U = L - V, P = L - min(N-M,L);
    
    auto &z = iv->second; H = z.size();  
    
    cout << "v = " << v << ", V = " << V << ", M = " << M << ", P = " << P << endl;

    for( auto p: exists )
        cout << p.second << " at index " << p.first << endl;
    
    cout << U << "-out-of-" << H << " instance(s) of " << u <<  " at index(es)" << endl;
    
    for( auto q: z )
        cout << q << ' ';
}

The input to the program for your example is:

2 5

*+

1 3 2 1 4

and the program output is:

v = 3, V = 2, M = 2, P = 0

3 at index 1

4 at index 4

1-out-of-1 instance(s) of 2 at index(es)

2

=====

Used: 15 ms, 3264 KB

Hope that these observations help.