If the problem instance has N intersection sets, then you can think of tuples in the product as an N-dimensional "rectangular" grid, where each tuple corresponds to a grid element. You will start by emitting max. The total set [9,4,5], which is located in one corner of the grid.
" " , . , "" . - , .
, , . , .
[9,4,5]
[8,4,5] (one smaller on first dimension)
[9,2,5] (one smaller on second dimension)
[9,4,1] (one smaller on third dimension)
. [8,4,5].
[0,4,5], [8,2,5], [8,4,1]
,
[9,2,5], [9,4,1], [0,4,5], [8,2,5], [8,4,1]
. [9,2,5]. -
[8,2,5], [9,2,1].
,
[9,4,1], [0,4,5], [8,2,5], [8,4,1], [9,2,1]
[8,2,5] . .
- [8,2,5]. -
[0,2,5], [8,2,1]
.
. O (log | C |), C - .
? . . , ,
|C| = O(|A1||A2| + |A2||A3| + |A1||A3|)
,
O(log(|A1||A2| + |A2||A3| + |A1||A3|))
N, O (log 3 N ^ 2) = O (log 3 + 2 log N) = O (log N).
A1 A1 A2 || A3 | , O (N ^ 3).
O (log N ^ 3) = O (3 log N) = O (log N). 50% , . , O (N). / - O (N ^ 2).
Java, .
import java.util.Arrays;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;
public class SortedProduct {
final SortedTuple [] tuples;
final NoDupHeap candidates = new NoDupHeap();
SortedProduct(SortedTuple [] tuple) {
this.tuples = Arrays.copyOf(tuple, tuple.length);
reset();
}
static class SortedTuple {
final int [] elts;
SortedTuple(int... elts) {
this.elts = Arrays.copyOf(elts, elts.length);
Arrays.sort(this.elts);
}
@Override
public String toString() {
return Arrays.toString(elts);
}
}
class RefTuple {
final int [] refs;
final int sum;
RefTuple(int [] index, int sum) {
this.refs = index;
this.sum = sum;
}
RefTuple getSuccessor(int i) {
if (refs[i] == 0) return null;
int [] newRefs = Arrays.copyOf(this.refs, this.refs.length);
int j = newRefs[i]--;
return new RefTuple(newRefs, sum - tuples[i].elts[j] + tuples[i].elts[j - 1]);
}
int [] getTuple() {
int [] val = new int[refs.length];
for (int i = 0; i < refs.length; ++i)
val[i] = tuples[i].elts[refs[i]];
return val;
}
@Override
public int hashCode() {
return Arrays.hashCode(refs);
}
@Override
public boolean equals(Object o) {
if (o instanceof RefTuple) {
RefTuple t = (RefTuple) o;
return Arrays.equals(refs, t.refs);
}
return false;
}
}
RefTuple getInitialCandidate() {
int [] index = new int[tuples.length];
int sum = 0;
for (int j = 0; j < index.length; ++j)
sum += tuples[j].elts[index[j] = tuples[j].elts.length - 1];
return new RefTuple(index, sum);
}
final void reset() {
candidates.clear();
candidates.add(getInitialCandidate());
}
int [] getNext() {
if (candidates.isEmpty()) return null;
RefTuple next = candidates.poll();
for (int i = 0; i < tuples.length; ++i) {
RefTuple successor = next.getSuccessor(i);
if (successor != null) candidates.add(successor);
}
return next.getTuple();
}
static class NoDupHeap {
final PriorityQueue<RefTuple> heap =
new PriorityQueue<>((a, b) -> Integer.compare(b.sum, a.sum));
final Set<RefTuple> set = new HashSet<>();
void add(RefTuple t) {
if (set.contains(t)) return;
heap.add(t);
set.add(t);
}
RefTuple poll() {
RefTuple t = heap.poll();
set.remove(t);
return t;
}
boolean isEmpty() {
return heap.isEmpty();
}
void clear() {
heap.clear();
set.clear();
}
}
public static void main(String [] args) {
SortedTuple [] tuples = {
new SortedTuple(9, 8, 0),
new SortedTuple(4, 2),
new SortedTuple(5, 1),
};
SortedProduct product = new SortedProduct(tuples);
for (;;) {
int[] next = product.getNext();
if (next == null) break;
System.out.println(Arrays.toString(next));
}
}
}