3

I was working on something, and I was able to reduce a problem to a particular form: given n tuples each of k integers, say: (a1,a2,a3,a4) , (b1,b2,b3,b4) , (c1,c2,c3,c4) , (d1,d2,d3,d4), I wish to choose any number of tuples, that, when added to each other, give a tuple with no positive elements. If I choose tuples a and b, I get tuple (a1+b1,a2+b2,a3+b3,a4+b4). So, if a = (1,-2,2,0) and b=(-1, 1, -3,0) then a+b =(0,-1,-1,0) which includes no positive numbers, hence is a solution of the problem.

Is there a way to obtain a solution (or verify its nonexistence) using a method other than checking the sum of all subset tuples, which takes 2^n steps?

Since this question is from my head, and not a particular textbook, I do not know the proper way to express it, and research to find an answer has been completely futile. Most of my searches directed me to the subset sum problem, where we choose k elements from a list that sum to a particular question. My problem could be said to be a complication of that: we choose a group of tuples from a list, and we want the sum of each element in these tuples to be <=0.

Edit: Thanks to the link provided, and due to the comments that indicated that a less than exponential solution is difficult, solving the question for the tuples whose elements range between -1,0, and 1 will be enough for me. Furthermore, the tuples will have ranging from 10,000-20,000 integers, and there will be no more than 1000 tuples. Each tuple has at most 10 1's, and 10 -1's, and the rest are zeroes

If anyone could also prove that it is some sort of NP, that would be great.

I failed to come up with a DP solution, and sorting doesn't seem useful

Confused Soul
  • 358
  • 2
  • 12
  • 1
    I think this can be somewhat abtracted/generalized/simplified to "combinations of integers that give a positive/negative sum". For the tuples, you could use that for each position in the tuple and get the intersection of those. Maybe it's easier to find an existing algorithm for that. – tobias_k Jun 02 '19 at 09:20
  • Thanks for the idea. Assuming that I wish to use that method, then for each position, I need to find all the valid combinations of the positions, and then do their intersection. I am obliged to find all combinations for each position because omitting one can be omitting a potential solution. And that means I'm still stuck at 2^n. – Confused Soul Jun 02 '19 at 10:36
  • Similar to [How to find multidimensional path of exact 0 cost with 1, 0, -1 weights](https://stackoverflow.com/questions/55908423/how-to-find-multidimensional-path-of-exact-0-cost-with-1-0-1-weights). This may give you hints as to what keywords to search for. – RobertBaron Jun 02 '19 at 10:44
  • Intuitively, I think finding a solution is indeed O(2^n), but with a good heuristic maybe you can do better in the average case. E.g., you could try some greedy algorithm: Start with the tuple with the lowest (squared?) positive numbers (i.e. where `max` or `sum` of `x^2 for x in t if x > 0` is minimal), then pick the next tuple such that the positive numbers for the combination are minimal, and repeat, or backtrack if you can't find a solution on the current path. – tobias_k Jun 02 '19 at 11:02
  • What's the range each element can take? – גלעד ברקן Jun 02 '19 at 11:23
  • Edited question to include new restriction, based on link – Confused Soul Jun 02 '19 at 11:31
  • We can have a pseudo polynomial time solution (`O(n^5)`) based on dynamic programming (similar to subset sum pseudo DP) if we can bound the total sum of the tuples. The constraint you supply guarantees that. How many dimensions does a tuple have? Can I assume it as 4, as provided in your question? – Mukul Gupta Jun 02 '19 at 11:43

1 Answers1

1

This can be solved in pseudo polynomial time with the given constraints using dynamic programming.

Explanation

This is similar to the pseudo polynomial time dynamic programming solution for the subset sum problem. It is only extended to multiple dimensions (4).

Time complexity

O(n * sum4) or in this case, since sum has been bounded by n, O(n5)

Solution

Demo

Here is a top-down dynamic programming solution with memoization in C++.

const int N = 50;
int a[50][4]= {{0, 1, -1, 0},
          {1, -1, 0, 0},
          {-1, -1, 0, -1}};

unordered_map<int, bool> dp[N];

bool subset(int n, int sum1, int sum2, int sum3, int sum4)
{
  // Base case: No tuple selected
  if (n == -1  && !sum1 && !sum2 && !sum3 && !sum4)
    return true;
  // Base case: No tuple selected with non-zero sum
  else if(n == -1)
    return false;
  else if(dp[n].find(hashsum(sum1, sum2, sum3, sum4)) != dp[n].end() )
    return dp[n][hashsum(sum1, sum2, sum3, sum4)];

  // Include the current element
  bool include = subset(n - 1,
    sum1 - a[n][0],
    sum2 - a[n][1],
    sum3 - a[n][2],
    sum4 - a[n][3]);
  // Exclude the current element
  bool exclude = subset(n - 1, sum1, sum2, sum3, sum4);

  return dp[n][hashsum(sum1, sum2, sum3, sum4)] = include || exclude;
}

For memoization, the hashsum is calculated as follows:

int hashsum(int sum1, int sum2, int sum3, int sum4) {
  int offset = N;
  int base = 2 * N;
  int hashSum = 0;
  hashSum += (sum1 + offset) * 1;
  hashSum += (sum2 + offset) * base;
  hashSum += (sum3 + offset) * base * base;
  hashSum += (sum4 + offset) * base * base * base;
  return hashSum;
}

The driver code can then search for any non-positive sum as follows:

int main()
{
  int n = 3;
  bool flag = false;
  int sum1, sum2, sum3, sum4;
  for (sum1 = -n; sum1 <= 0; sum1++) {
    for (sum2 = -n; sum2 <= 0; sum2++) {
      for (sum3 = -n; sum3 <= 0; sum3++) {
        for (sum4 = -n; sum4 <= 0; sum4++) {
          if (subset(n - 1, sum1, sum2, sum3, sum4)) {
            flag = true;
            goto done;
          }
        }
      }
    }
  }
  done:
  if (flag && (sum1 || sum2 || sum3 || sum4))
    cout << "Solution found. " << sum1 << ' ' << sum2 << ' ' << sum3 << ' ' << sum4 << std::endl;
  else
    cout << "No solution found.\n";
  return 0;
}

Note that a trivial solution with sums (0, 0, 0, 0} where no element is ever selected always exists and thus is left out in the driver code.

Mukul Gupta
  • 2,310
  • 3
  • 24
  • 39
  • The sum of elements in one tuple, in my application, can be indeed bounded by 5. However the dimension is expected to be in the thousands (mainly 0's). Your approach still works? (I'll modify it myself if it does, right after I read some refreshers on the 1-D subset sum – Confused Soul Jun 02 '19 at 16:14
  • @ConfusedSoul Unfortunately, not. This approach scales well with smaller bounded sums but is exponential in number of dimensions. – Mukul Gupta Jun 02 '19 at 16:18
  • 1
    So even if the bounded sum is low, if the dimensions are high it is still exponential? I will nonetheless do my research, and try seeing if I can get a workaround based on your kind work. . thank you sincerely for the code, the guidance and the effort. – Confused Soul Jun 02 '19 at 16:19
  • As a corollary to your added restrictions where the sum can be max 5, can I assume that the number of elements is also capped by 10? In such a case, an exponential algorithm to generate all subsets would work fine. – Mukul Gupta Jun 02 '19 at 16:23
  • Number of elements per tuple? Expected to be in the thousands unfortunately. However the number of tuples itself is likely to be in the hundreds. – Confused Soul Jun 02 '19 at 16:27
  • @ConfusedSoul I would add the number of expected tuples and their dimensions to the question description. That makes a significant difference. – גלעד ברקן Jun 02 '19 at 16:54
  • Yes, you are right. But it is only now that I figured the bounds out. I will edit my question to include the new rough limits. – Confused Soul Jun 02 '19 at 17:22