我有一组K元素,我需要创建一个N有序元素的组合 例如,如果K = 1并且我有{X1,空集}和n = 2那么我有一个有序的对我需要这样做:
例1:
({},{})
({X1},{}), ({},{X1})
({X1},{X1})
请注意,我需要按此顺序获取元素:首先将0节点的元素作为两个对的总和,第二个元素为1,ecc
我的想法是制作初始集的部分集合,在时间添加元素,但我正在失去理智。有什么建议?我需要在java中执行此操作。
编辑1: 换句话说,我需要创建一个Hasse图: http://en.wikipedia.org/wiki/Hasse_diagram
其中每个节点都是部件集的一个元素,而部分排序函数包含在所有子集上,如下所示:
示例2:
ni =(S1i,S2i)C nj =(S1j,S2j)仅当S1i C S1j和S21 C s2j
EDIT2:@RONALD:
如果我有一个S = {1,2}和n = 2的K = 2,我需要这个输出:
level0: ({}, {})
level1: ({1}, {}); ({2}, {}); ({}, {1}); ({}, {2})
level2: ({1,2}, {}); ({1}, {1}); ({1}, {2}); ({2}, {1}); ({2}, {2}); ({}, {1,2});
[..]
级别之间的顺序很重要,例如:
如果在level1我有
({1}, {}); ({2}, {}); ({}, {1}); ({}, {2})
OR
({}, {2}); ({}, {1}); ({2}, {}); ({1}, {});
是一回事。但重要的是,在第2级我拥有level2的所有超集,并且在示例2
中解释了超集 EDIT3:
如果我的集合是S = {x,y,z}并且我每个节点只有一个集合,那么结果(从底部开始)是这样的:
http://upload.wikimedia.org/wikipedia/commons/e/ea/Hasse_diagram_of_powerset_of_3.svg
如果我有S = {1,2}且每个点头两套,结果就是这个(感谢Ronald的图表):
http://www.independit.de/Downloads/hasse.pdf
EDIT4:
因为是一个超指数问题,我的想法是:我计算一个级别(在有序模式下!)并且通过一些规则我修剪一个节点和他的所有超集。另一个停止规则可能是停在某个水平。对于此规则,必须直接以有序的方式计算组合而不是来计算所有然后重新排序。
EDIT5:
Marco13的代码工作正常,我已经做了一些修改:
现在算法做了所有,但我需要加快它。有没有办法并行计算?这种方式使用Map Reduce(Apache hadoop实现)范例?
package utilis;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HasseDiagramTest4
{
public static void main(String[] args)
{
int numberOfSetsPerNode = 3;
List<Integer> set = Arrays.asList(1, 2, 3, 4, 5,6);
List<Set<Integer>> powerSet = computePowerSet(set);
powerSet = KPowerSet(powerSet, 3);
List<List<Set<Integer>>> prunedNodes =
new ArrayList<List<Set<Integer>>>();
List<Set<Integer>> prunedNode = new ArrayList<Set<Integer>>();
HashSet<Integer> s = new HashSet<Integer>();
HashSet<Integer> s_vuoto = new HashSet<Integer>();
s.add(1);
s.add(2);
prunedNode.add(s);
prunedNode.add(s_vuoto);
prunedNode.add(s);
prunedNodes.add(prunedNode);
compute(ordina(powerSet), numberOfSetsPerNode, prunedNodes);
}
private static <T> HashMap<Integer, List<Set<T>>> ordina(List<Set<T>> powerSet) {
HashMap<Integer, List<Set<T>>> hs = new HashMap<Integer, List<Set<T>>>();
for(Set<T> l: powerSet)
{
List<Set<T>> lput = new ArrayList<Set<T>>();
if(hs.containsKey(l.size()))
{
lput = hs.get(l.size());
lput.add(l);
hs.put(l.size(), lput);
}
else
{
lput.add(l);
hs.put(l.size(), lput);
}
}
return hs;
}
private static <T> List<Set<T>> KPowerSet(List<Set<T>> powerSet, int k)
{
List<Set<T>> result = new ArrayList<Set<T>>();
for(Set<T>s:powerSet)
{
if(s.size() <= k)
{
result.add(s);
}
}
return result;
}
private static <T> List<Set<T>> computePowerSet(List<T> set)
{
List<Set<T>> result = new ArrayList<Set<T>>();
int numElements = 1 << set.size();
for (int j=0; j<numElements; j++)
{
Set<T> element = new HashSet<T>();
for (int i = 0; i < set.size(); i++)
{
long b = 1 << i;
if ((j & b) != 0)
{
element.add(set.get(i));
}
}
result.add(element);
}
return result;
}
private static List<Integer> createList(int numberOfElements)
{
List<Integer> list = new ArrayList<Integer>();
for (int i=0; i<numberOfElements; i++)
{
list.add(i+1);
}
return list;
}
private static <T> void compute(
HashMap<Integer, List<Set<T>>> powerSet, int numberOfSetsPerNode,
List<List<Set<T>>> prunedNodes)
{
Set<List<Set<T>>> level0 = createLevel0(numberOfSetsPerNode);
System.out.println("Level 0:");
print(level0);
Set<List<Set<T>>> currentLevel = level0;
int level = 0;
while (true)
{
Set<List<Set<T>>> nextLevel =
createNextLevel(currentLevel, powerSet, prunedNodes);
if (nextLevel.size() == 0)
{
break;
}
System.out.println("Next level: "+nextLevel.size()+" nodes");
print(nextLevel);
currentLevel = nextLevel;
level++;
}
}
private static <T> Set<List<Set<T>>> createLevel0(int numberOfSetsPerNode)
{
Set<List<Set<T>>> level0 =
new LinkedHashSet<List<Set<T>>>();
List<Set<T>> level0element = new ArrayList<Set<T>>();
for (int i=0; i<numberOfSetsPerNode; i++)
{
level0element.add(new LinkedHashSet<T>());
}
level0.add(level0element);
return level0;
}
private static <T> List<Set<T>> getNext(Set<T> current, HashMap<Integer, List<Set<T>>> powerSet)
{
ArrayList<Set<T>> ritorno = new ArrayList<Set<T>>();
int level = current.size();
List<Set<T>> listnext = powerSet.get(level+1);
if(listnext != null)
{
for(Set<T> next: listnext)
{
if(next.containsAll(current))
{
ritorno.add(next);
}
}
}
return ritorno;
}
private static <T> Set<List<Set<T>>> createNextLevel(
Set<List<Set<T>>> currentLevel, HashMap<Integer, List<Set<T>>> powerSet,
List<List<Set<T>>> prunedNodes)
{
Set<List<Set<T>>> nextLevel = new LinkedHashSet<List<Set<T>>>();
//Per ogni nodo del livello corrente
for (List<Set<T>> currentLevelElement : currentLevel)
{
//Per ogni insieme del nodo preso in considerazione
for (int i=0; i<currentLevelElement.size(); i++)
{
List<Set<T>> listOfnext = getNext (currentLevelElement.get(i), powerSet);
for (Set<T> element : listOfnext)
{
List<Set<T>> nextLevelElement = copy(currentLevelElement);
Set<T> next = element;
nextLevelElement.remove(i);
nextLevelElement.add(i, next);
boolean pruned = false;
for (List<Set<T>> prunedNode : prunedNodes)
{
if (isSuccessor(prunedNode, nextLevelElement))
{
pruned = true;
}
}
if (!pruned)
{
nextLevel.add(nextLevelElement);
}
else
{
System.out.println("Pruned "+nextLevelElement+ " due to "+prunedNodes);
}
}
}
}
return nextLevel;
}
private static <T> boolean isSuccessor(
List<Set<T>> list, List<Set<T>> successor)
{
for (int i=0; i<list.size(); i++)
{
Set<T> set = list.get(i);
Set<T> successorSet = successor.get(i);
//System.out.println("Successor:" + successorSet + "pruned:" + set);
if (!successorSet.containsAll(set))
{
return false;
}
}
return true;
}
private static <T> List<Set<T>> copy(List<Set<T>> list)
{
List<Set<T>> result = new ArrayList<Set<T>>();
for (Set<T> element : list)
{
result.add(new LinkedHashSet<T>(element));
}
return result;
}
private static <T> void print(
Iterable<? extends Collection<? extends Collection<T>>> sequence)
{
for (Collection<? extends Collection<T>> collections : sequence)
{
System.out.println(" "+collections);
}
}
}
答案 0 :(得分:1)
因此,如果您有一个基本集S = {1, 2}
,则K = 2
和S的子集集合为{{}, {1}, {2}, {1,2}}
。假设 n 仍为2.那么您的输出将类似于
({}, {})
({1}, {}); ({2}, {}); ({}, {1}); ({}, {2})
({1,2}, {}); ({}, {1,2})
({1}, {1}); ({1}, {2}); ({2}, {1}); ({2}, {2})
({1}, {1,2}); ({1,2}, {1}); ({2}, {1,2}); ({1,2}, {2})
({1,2}, {1,2})
正确?输出的排序有点困难,因为结果没有完全排序。但它仍然归结为计数。不像我最初想的那样,(K + 1) - 但是更多(2 ^ K)-ary。
为了确定一个集合是否是另一个集合的子集,使用素数可能是一个想法。
您为原始集的每个元素分配素数。在我的例子中,那将是2和3.可以通过生成素数的所有乘积来构建子集集。在我的例子中,{1 /* empty set */, 2, 3, 6}
。
如果你有两套,由你的产品代表,很容易测试包含:
if (a % b == 0) then b is a subset of a
这只是一堆想法,但它们可能会帮助您找到解决方案。当然,主要技巧仅适用于原始集合中相对较少数量的元素,但只要K和N增长,您就会遇到问题。 (输出中的元素数量为(2^K)^N = 2^(NK)
。如果K == N == 5
,您将拥有2^(5 * 5) = 2^25
,大约3200万个输出元素。而这里的主要思想仍然有效。
编辑:我写了一个小的Java程序来展示我的想法。
javac Hasse.java
java Hasse > hasse.dot
dot -Tpdf -ohasse.pdf hasse.dot
acroread hasse.pdf
源代码:
import java.lang.*;
import java.util.*;
public class Hasse {
private static int K[] = { 1, 2, 3 };
private static int N = 2;
private static int prime[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 };
//
// PK[0][] is the array of "subsets"
// PK[1][] is the array of number of elements of K participating in the subset
//
private static int PK[][];
// some constants; the initialization is clear enough
private static final long twoNK = pow(2, N * K.length);
private static final int twoK = (int) pow(2, K.length);
private static final int NK = N * K.length;
private static final long NKf = fac(NK);
//
// this power function isn't suitable for large powers
// but in the range we are working, it's OK
//
public static long pow(int b, int p)
{
long result = 1;
for (int i = 0; i < p; ++i)
result *= b;
return result;
}
// fac calculates n! (needed for the a over b calculation)
public static long fac(int n)
{
long result = 1;
for (int i = n; i > 0; --i) result *= i;
return result;
}
//
// constructPK builds the set of subsets of K
// a subset is represented by a product of primes
// each element k_i of K has an associated prime p_i
// since the prime factorization of a number is unique,
// the product can be translated into a subset and vice versa
//
public static void constructPK()
{
int i, cnt;
int numElms = twoK;
PK = new int[2][numElms];
for (i = 0; i < numElms; ++i) {
int j = i;
cnt = 0;
PK[0][i] = 1;
PK[1][i] = 0;
while (j > 0) {
if (j % 2 == 1) {
PK[0][i] *= prime[cnt];
PK[1][i]++;
}
cnt++;
j /= 2;
}
}
}
// we have a k-ary number (that is: binary if k == 2, octal if k == 8
// and so on
// the addOne() function calculates the next number based on the input
public static void addOne(int kAry[])
{
int i = 0;
kAry[i] += 1;
while (kAry[i] >= twoK) {
kAry[i] = 0;
++i;
kAry[i] += 1;
}
}
// the addN() function is similar to the addOne() function
// with the difference that it add n to the input, not just 1
public static void addN(int kAry[], int n)
{
int i = 0;
kAry[i] += n;
for (i = 0; i < N - 1; ++i) {
while (kAry[i] >= twoK) {
kAry[i] -= twoK;
kAry[i+1] += 1;
}
}
}
// from the k-ary number, which represents a node in the graph,
// the "level" is calculated.
public static int getLevel(int kAry[])
{
int level = 0;
for (int i = 0; i < N; ++i) {
level += PK[1][kAry[i]];
}
return level;
}
// output function for a node
public static String renderNode(int kAry[])
{
StringBuffer sb = new StringBuffer();
String sep = "";
sb.append("(");
for (int i = 0; i < N; ++i) {
String setSep = "";
int p = PK[0][kAry[i]];
sb.append(sep);
sb.append("{");
for (int j = 0; j < K.length; ++j) {
if (p % prime[j] == 0) {
sb.append(setSep + K[j]);
setSep = ", ";
}
}
sb.append("}");
sep = ", ";
}
sb.append(")");
return sb.toString();
}
// This function calculates the numerical representation
// of a node, addressed by its level and position within the level,
// in the k-ary number system
// if there's a more elegant way of finding the node, it would
// largely speed up the calculation, since this function is needed
// for calculating the edges
public static int[] getKAry(int level, int node)
{
int kAry[] = new int[N];
int nodesSoFar = 0;
for (int i = 0; i < N; ++i) kAry[i] = 0;
for (int cnt = 0; cnt < twoNK; ++cnt) {
if (getLevel(kAry) == level) {
if (nodesSoFar == node) {
return kAry;
} else
nodesSoFar++;
}
if (cnt + 1 < twoNK)
addOne(kAry);
}
return null;
}
// this function converts the decimal nodeNumber to
// its k-ary representation
public static int[] getKAry(int nodeNumber)
{
int kAry[] = new int[N];
for (int i = 0; i < N; ++i) kAry[i] = 0;
addN(kAry, nodeNumber);
return kAry;
}
public static String getLabel(int level, int node)
{
int kAry[] = getKAry(level, node);
return (kAry == null ? "Oops!" : renderNode(kAry));
}
public static void printPK()
{
System.out.println("# Number of elements: " + PK[0].length);
for (int i = 0; i < PK[0].length; ++i) {
System.out.println("# PK[0][" + i + "] = " + PK[0][i] + ",\tPK[1][" + i + "] = " + PK[1][i]);
}
}
public static void printPreamble()
{
System.out.println("digraph G {");
System.out.println("ranksep = 3");
System.out.println();
}
public static void printEnd()
{
System.out.println("}");
}
public static void printNodes()
{
int numNodes;
for (int i = 0; i <= NK; ++i) {
int level = i + 1;
numNodes = (int) (NKf / (fac(i) * fac(NK - i)));
for (int j = 0; j < numNodes; ++j) {
System.out.println("level_" + level + "_" + (j+1) + " [shape=box,label=\"" + getLabel(i, j) + "\"];");
}
System.out.println();
}
System.out.println();
}
// having two vectors of "sets", this function determines
// if each set in the ss (small set) vector is a subset of
// the corresponding set in the ls (large set) vector
public static boolean isSubset(int ss[], int ls[])
{
for (int i = 0; i < N; ++i)
if (PK[0][ls[i]] % PK[0][ss[i]] != 0) return false;
return true;
}
// this function finds and prints the edges
// it is called about twoNK times (once for each node)
// therefore performance optimizations have to be done here
public static void printEdges(int level, int node, int nodeNumber)
{
int kAry[] = getKAry(node);
int nlAry[];
int numNodes = (int) (NKf / (fac(level + 1) * fac(NK - level - 1)));
String myNode = "level_" + (level + 1) + "_" + (node + 1);
for (int i = 0; i < numNodes; ++i) {
nlAry = getKAry(level + 1, i);
if (nlAry == null) System.exit(1);
if (isSubset(kAry, nlAry)) {
System.out.println(myNode + " -> level_" + (level + 2) + "_" + (i + 1));
}
}
}
// this function renders the dot file
// first some initial text (preamble),
// then the nodes and the edges
// and finally the closing brace
public static void renderDot()
{
int numNodes;
int nodeNumber = 0;
printPreamble();
printNodes();
for (int level = 0; level < NK; ++level) {
numNodes = (int) (NKf / (fac(level) * fac(NK - level)));
for (int node = 0; node < numNodes; ++node) {
// find the edges to the nodes on the next level
printEdges(level, node, nodeNumber);
++nodeNumber;
}
System.out.println();
}
printEnd();
}
public static void main (String argv[])
{
constructPK();
renderDot();
}
}
答案 1 :(得分:1)
正如评论中所提到的,我很确定实际应该做什么的形式化要么不清楚,要么明显错误。比较“节点”的标准与示例不匹配。但是,一旦指定了排序标准(以Comparator
的形式),这应该很容易实现。
这里,比较两个“节点”的标准是节点中所有集合的大小的总和,它与给出的示例相匹配(虽然它直观地没有意义,因为它不对应任何真实的子集关系....)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class HasseDiagramTest
{
public static void main(String[] args)
{
List<Integer> set = Arrays.asList(1, 2);
List<List<Integer>> powerSet = computePowerSet(set);
List<List<List<Integer>>> combinations =
computeCombinations(powerSet, 2);
Comparator<List<List<Integer>>> comparator = createComparator();
Collections.sort(combinations, comparator);
List<List<List<List<Integer>>>> levels = createLevels(combinations);
for (List<List<List<Integer>>> level : levels)
{
System.out.println(level);
}
}
private static <T> List<List<List<List<T>>>> createLevels(
List<List<List<T>>> sortedCombinations)
{
List<List<List<List<T>>>> levels = new ArrayList<List<List<List<T>>>>();
int previousTotalSize = -1;
List<List<List<T>>> currentLevel = null;
for (int i=0; i<sortedCombinations.size(); i++)
{
List<List<T>> combination = sortedCombinations.get(i);
int totalSize = totalSize(combination);
if (previousTotalSize != totalSize)
{
previousTotalSize = totalSize;
currentLevel = new ArrayList<List<List<T>>>();
levels.add(currentLevel);
}
currentLevel.add(combination);
}
return levels;
}
private static <T> Comparator<List<List<T>>> createComparator()
{
return new Comparator<List<List<T>>>()
{
@Override
public int compare(List<List<T>> list0, List<List<T>> list1)
{
return Integer.compare(totalSize(list0), totalSize(list1));
}
};
}
private static <T> int totalSize(List<List<T>> lists)
{
int totalSize = 0;
for (List<T> list : lists)
{
totalSize += list.size();
}
return totalSize;
}
private static <T> List<List<T>> computePowerSet(List<T> set)
{
List<List<T>> result = new ArrayList<List<T>>();
int numElements = 1 << set.size();
for (int j=0; j<numElements; j++)
{
List<T> element = new ArrayList<T>();
for (int i = 0; i < set.size(); i++)
{
long b = 1 << i;
if ((j & b) != 0)
{
element.add(set.get(i));
}
}
result.add(element);
}
return result;
}
private static <T> List<List<T>> computeCombinations(List<T> list, int sampleSize)
{
int numElements = (int) Math.pow(list.size(), sampleSize);
int chosen[] = new int[sampleSize];
List<List<T>> result = new ArrayList<List<T>>();
for (int current = 0; current < numElements; current++)
{
List<T> element = new ArrayList<T>(sampleSize);
for (int i = 0; i < sampleSize; i++)
{
element.add(list.get(chosen[i]));
}
result.add(element);
increase(chosen, list.size());
}
return result;
}
private static void increase(int chosen[], int inputSize)
{
int index = chosen.length - 1;
while (index >= 0)
{
if (chosen[index] < inputSize - 1)
{
chosen[index]++;
return;
}
chosen[index] = 0;
index--;
}
}
}
答案 2 :(得分:1)
经过4次EDIT和大量讨论之后,这个应用程序的目标正逐渐变得清晰起来。实际上,人们必须考虑适当的形式化,但最终似乎并不那么困难。
与我的第一个答案(https://stackoverflow.com/a/22092523)相反,这个新答案会迭代地计算上一级别的下一级别(而createNextLevel
的核心,只有10行代码)。< / p>
在compute
方法中,“EDIT4”中要求的修剪可以集成到while
循环中。
编辑:评论中还有更多请求。整合它们。但这变得荒谬可笑。 Um den Rest kannst du dichselbstkümmern。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class HasseDiagramTest2
{
public static void main(String[] args)
{
int numberOfElements = 2;
int numberOfSetsPerNode = 2;
List<Integer> list = createList(numberOfElements);
List<List<Set<Integer>>> prunedNodes =
new ArrayList<List<Set<Integer>>>();
List<Set<Integer>> prunedNode = new ArrayList<Set<Integer>>();
prunedNode.add(Collections.singleton(1));
prunedNode.add(Collections.singleton(1));
prunedNodes.add(prunedNode);
compute(list, numberOfSetsPerNode, prunedNodes);
}
private static List<Integer> createList(int numberOfElements)
{
List<Integer> list = new ArrayList<Integer>();
for (int i=0; i<numberOfElements; i++)
{
list.add(i+1);
}
return list;
}
private static <T> void compute(
List<T> elements, int numberOfSetsPerNode,
List<List<Set<T>>> prunedNodes)
{
Set<List<Set<T>>> level0 = createLevel0(numberOfSetsPerNode);
System.out.println("Level 0:");
print(level0);
Set<List<Set<T>>> currentLevel = level0;
int level = 0;
while (true)
{
Set<List<Set<T>>> nextLevel =
createNextLevel(currentLevel, elements, prunedNodes);
if (nextLevel.size() == 0)
{
break;
}
System.out.println("Next level: "+nextLevel.size()+" nodes");
print(nextLevel);
currentLevel = nextLevel;
level++;
}
}
private static <T> Set<List<Set<T>>> createLevel0(int numberOfSetsPerNode)
{
Set<List<Set<T>>> level0 =
new LinkedHashSet<List<Set<T>>>();
List<Set<T>> level0element = new ArrayList<Set<T>>();
for (int i=0; i<numberOfSetsPerNode; i++)
{
level0element.add(new LinkedHashSet<T>());
}
level0.add(level0element);
return level0;
}
private static <T> Set<List<Set<T>>> createNextLevel(
Set<List<Set<T>>> currentLevel, List<T> elements,
List<List<Set<T>>> prunedNodes)
{
Set<List<Set<T>>> nextLevel = new LinkedHashSet<List<Set<T>>>();
for (List<Set<T>> currentLevelElement : currentLevel)
{
for (int i=0; i<currentLevelElement.size(); i++)
{
for (T element : elements)
{
List<Set<T>> nextLevelElement = copy(currentLevelElement);
Set<T> next = nextLevelElement.get(i);
boolean changed = next.add(element);
if (!changed)
{
continue;
}
boolean pruned = false;
for (List<Set<T>> prunedNode : prunedNodes)
{
if (isSuccessor(prunedNode, nextLevelElement))
{
pruned = true;
}
}
if (!pruned)
{
nextLevel.add(nextLevelElement);
}
else
{
// System.out.println(
// "Pruned "+nextLevelElement+
// " due to "+prunedNodes);
}
}
}
}
return nextLevel;
}
private static <T> boolean isSuccessor(
List<Set<T>> list, List<Set<T>> successor)
{
for (int i=0; i<list.size(); i++)
{
Set<T> set = list.get(i);
Set<T> successorSet = successor.get(i);
if (!successorSet.containsAll(set))
{
return false;
}
}
return true;
}
private static <T> List<Set<T>> copy(List<Set<T>> list)
{
List<Set<T>> result = new ArrayList<Set<T>>();
for (Set<T> element : list)
{
result.add(new LinkedHashSet<T>(element));
}
return result;
}
private static <T> void print(
Iterable<? extends Collection<? extends Collection<T>>> sequence)
{
for (Collection<? extends Collection<T>> collections : sequence)
{
System.out.println(" "+collections);
}
}
}