- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
tl;博士我的递归关系解释的图表数量少于应有的数量。
我需要找出具有 N 个标记顶点和 K 个未标记边的简单连通图的数量。 Link to full source with complete question
[我看过this post它没有解决我的问题]
约束:2 <= N <= 20。因此,N-1 <= K <= N(N-1)/2。
我用两种不同的(不完全是,我后来意识到)想法来解决这个问题。
第一个想法:用 K 条边连接 N 个节点,使得 2 个节点之间有 1 条路径
思路:考虑N-1
节点和K-1
边。添加第N个节点有多少种方法?
N
和任何其他 N-1
节点之间分配 1 条边;这是微不足道的,\binom {N-1}1,即给定 N-1
选择 1。N-1
条边。我们只看 K ∈ [N-1, N(N-1)/2] 的值(其他值没有意义)。当 K = N-1 时,它基本上属于 Cayley's formula。 .递归关系是我想出的部分。 问题是我考虑的图表数量少于应有的数量。代码:
static Map<List<Integer>, String> resultMap = new HashMap<List<Integer>, String>();
// N -> number of nodes
// K -> number of edges
// N will be at least 2 and at most 20.
// K will be at least one less than n and at most (n * (n - 1)) / 2
public static String answer(int N, int K) {
/* for the case where K < N-1 */
if(K < N-1)
return BigInteger.ZERO.toString();
/* for the case where K = N-1 */
// Cayley's formula applies [https://en.wikipedia.org/wiki/Cayley's_formula].
// number of trees on n labeled vertices is n^{n-2}.
if(K == N-1)
return BigInteger.valueOf((long)Math.pow(N, N-2)).toString();
/* for the case where K > N-1 */
// check if key is present in the map
List<Integer> tuple = Arrays.asList(N, K);
if( resultMap.containsKey(tuple) )
return resultMap.get(tuple);
// maximum number of edges in a simply
// connected undirected unweighted graph
// with n nodes = |N| * |N-1| / 2
int maxEdges = N * (N-1) / 2;
/* for the case where K = N(N-1)/2 */
// if K is the maximum possible
// number of edges for the number of
// nodes, then there is only one way is
// to make a graph (connect each node
// to all other nodes)
if(K == maxEdges)
return BigInteger.ONE.toString();
/* for the case where K > N(N-1)/2 */
if(K > maxEdges)
return BigInteger.ZERO.toString();
BigInteger count = BigInteger.ZERO;
for(int k = 1; k <= N-1 ; k++) {
BigInteger combinations = nChooseR(N-1, k);
combinations = combinations.multiply(new BigInteger(answer(N-1, K-k)));
count = count.add(combinations);
}
// unmodifiable so key cannot change hash code
resultMap.put(Collections.unmodifiableList(Arrays.asList(N, K)), count.toString());
return count.toString();
}
我找到了 this在 MSE 上发帖解决了同样的问题。使用它作为引用,“公式”看起来有点像这样: 这完全符合预期。此部分的代码如下。
static Map<List<Integer>, String> resultMap2 = new HashMap<List<Integer>, String>();
// reference: https://math.stackexchange.com/questions/689526/how-many-connected-graphs-over-v-vertices-and-e-edges
public static String answer2(int N, int K) {
/* for the case where K < N-1 */
if(K < N-1)
return BigInteger.ZERO.toString();
/* for the case where K = N-1 */
// Cayley's formula applies [https://en.wikipedia.org/wiki/Cayley's_formula].
// number of trees on n labeled vertices is n^{n-2}.
if(K == N-1)
return BigInteger.valueOf((long)Math.pow(N, N-2)).toString();
/* for the case where K > N-1 */
// check if key is present in the map
List<Integer> tuple = Arrays.asList(N, K);
if( resultMap2.containsKey(tuple) )
return resultMap2.get(tuple);
// maximum number of edges in a simply
// connected undirected unweighted graph
// with n nodes = |N| * |N-1| / 2
int maxEdges = N * (N-1) / 2;
/* for the case where K = N(N-1)/2 */
// if K is the maximum possible
// number of edges for the number of
// nodes, then there is only one way is
// to make a graph (connect each node
// to all other nodes)
if(K == maxEdges)
return BigInteger.ONE.toString();
/* for the case where K > N(N-1)/2 */
if(K > maxEdges)
return BigInteger.ZERO.toString();
// get the universal set
BigInteger allPossible = nChooseR(maxEdges, K);
BigInteger repeats = BigInteger.ZERO;
// now, to remove duplicates, or incomplete graphs
// when can these cases occur?
for(int n = 0 ; n <= N-2 ; n++) {
BigInteger choose_n_from_rem_nodes = nChooseR(N-1, n);
int chooseN = (N - 1 - n) * (N - 2 - n) / 2;
BigInteger repeatedEdges = BigInteger.ZERO;
for(int k = 0 ; k <= K ; k++) {
BigInteger combinations = nChooseR(chooseN, k);
BigInteger recurse = new BigInteger(answer2(n+1, K-k));
repeatedEdges = repeatedEdges.add(combinations.multiply(recurse));
}
repeats = repeats.add(choose_n_from_rem_nodes.multiply(repeatedEdges));
}
// remove repeats
allPossible = allPossible.subtract(repeats);
// add to cache
resultMap2.put(Collections.unmodifiableList(Arrays.asList(N, K)), allPossible.toString());
return resultMap2.get(tuple);
}
如果有人能指出我的方向,以便我可以在我的第一种方法中发现错误,我将不胜感激。第二种方法有效,但它会进行 O(NK) 次递归调用,并且 K 在 N 中平均为二次方。因此,显然不是很好,尽管我已尝试使用 DP 来最小化计算。 nChooseR() 和 factorial() 函数如下。
nChooseR 代码:
static Map<List<Integer>, BigInteger> nCrMap = new HashMap<List<Integer>, BigInteger>();
// formula: nCr = n! / [r! * (n-r)!]
private static BigInteger nChooseR(int n, int r) {
// check if key is present
List<Integer> tuple = Arrays.asList(n, r);
if( nCrMap.containsKey(tuple) )
return nCrMap.get(tuple);
// covering some basic cases using
// if statements to prevent unnecessary
// calculations and memory wastage
// given 5 objects, there are 0 ways to choose 6
if(r > n)
return BigInteger.valueOf(0);
// given 5 objects, there are 5 ways of choosing 1
// given 5 objects, there are 5 ways of choosing 4
if( (r == 1) || ( (n-r) == 1 ) )
return BigInteger.valueOf(n);
// given 5 objects, there is 1 way of choosing 5 objects
// given 5 objects, there is 1 way of choosing 0 objects
if( (r == 0) || ( (n-r) == 0 ) )
return BigInteger.valueOf(1);
BigInteger diff = getFactorial(n-r);
BigInteger numerator = getFactorial(n);
BigInteger denominator = getFactorial(r);
denominator = denominator.multiply(diff);
// unmodifiable so key cannot change hash code
nCrMap.put(Collections.unmodifiableList(Arrays.asList(n, r)), numerator.divide(denominator));
return nCrMap.get(tuple);
}
阶乘代码:
private static Map<Integer, BigInteger> factorials = new HashMap<Integer, BigInteger>();
private static BigInteger getFactorial(int n) {
if(factorials.containsKey(n))
return factorials.get(n);
BigInteger fact = BigInteger.ONE;
for(int i = 2 ; i <= n ; i++)
fact = fact.multiply(BigInteger.valueOf(i));
factorials.put(n, fact);
return fact;
}
部分测试代码:
public static void main(String[] args) {
int fail = 0;
int total = 0;
for(int n = 2 ; n <= 20 ; n++) {
for(int k = n-1 ; k <= n*(n-1)/2 ; k++) {
total++;
String ans = answer(n,k);
String ans2 = answer2(n,k);
if(ans.compareTo(ans2) != 0) {
fail++;
System.out.println("N = " + n + " , K = " + k + " , num = " + ans + " ||| " + ans2);
}
}
}
System.out.println("Approach 1 fails " + ((100*fail)/total) + "% of the test");
}
附言作为 Google Foobar 挑战的一部分,我接受了这个挑战。只是想让所有人都知道这一点。 answer2()
根据挑战者无法看到的 Foobar 上的测试用例判断为有效。只是为了阅读所有这些,这里有一个 video of a tiny hamster eating a tiny burrito .
最佳答案
另一种方法...
我们知道 f(n,n-1) = n^{n-2}
是个数的计数函数标记有根树 [Cayley 公式]
现在,令f(n, k)
为具有n 个节点和k 个边的连通图的总数,我们有一个关于如何添加新边缘的特征:
1) Take any graph in F[n,k], and you can add an edge between any of the {n \choose 2} - k pairs of unmatched nodes.
2) If you have two connected graphs g_1 and g_2, say in F[s, t] and F[n-s, k-t] respectively (that is, a connected graph with s nodes and t edges and a connected graph with n-s nodes and k-t edges), then you can surgically construct a new graph by connecting these two subgraphs together.
你有s * (n-s)
对顶点可供选择,你可以选择s 点
{n\choose s}
方式。然后你可以总结选择s
和 t
分别从 1 到 n-1
,这样做,你将有每张图重复计算两次。我们称此构造为 g(n, k)
。
然后 g(n,k) = (\sum_s,t {n\choose s} s (n-s) f(s,t) f(n-s, k-t))/2
现在,没有其他方法可以添加额外的边(不减少到上面的两个结构),所以加法项h(n,k+1) = (N - k)f(n,k) + g(n,k)
给出了我们已经得到的多组图的特征建。为什么这是一个多重集?
好吧,我们来看一个关于两个子案例的案例分析(对建筑的归纳)。在h(n, k+1)
图中取一个随机图g
以这种方式构建。归纳假设是,有k + 1
多重集 h(n, k+1)
中 g 的副本。
我们只看归纳案例如果您断开连接图中的一条边,那么它要么保持连接图或它分成两个连接的图。现在,固定在 edge e
上,如果你打破任何其他边缘,那么 e 仍然是在 (k+1) - 1
个不同的结构中。如果你打破 e
,你将拥有另一个独特的建筑。这意味着有 k + 1
种可能的不同图类(两个组件的任何一个组件)我们可以从中构造相同的最终图g
。
因此,h(n,k+1)
对每个图形总共计数了 k+1
次,依此类推f(n, k+1)
= h(n, k+1)/(k+1)
= ((N-k)f(n,k ) + g(n,k))/(k+1)
.
给定一个固定的n
和k
,这个循环将在O((nk)^2)
时间内计算出正确的结果,如此复杂,它等同于之前的算法。这种构造的好处在于它很容易产生解析生成函数,以便您可以对其进行分析。
在这种情况下,假设您有一个复值函数 f_k(x,y)
,然后
2 dy f_{k+1} = (x^2 dx^2 f_k - 2 y dy f_k) +\sum_s z^2 dz f_s dz f_{k-s}
。
您将需要大量复杂的分析机制来求解此递归 PDE。
这是一个 java 实现 [ source ]
关于java - 具有 N 个标记顶点和 K 个未标记边的简单连通图的数量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35743318/
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我们可以说 O(K + (N-K)logK)相当于O(K + N logK)对于 1 < = K <= N ? 最佳答案 简短的回答是它们不等价,这取决于k 的值。如果k等于N,那么第一个复杂度是O(
我有以下解决方案,但我从其他评论者那里听说它是 O(N * K * K),而不是 O(N * K)其中 N 是 K 列表的(最大)长度,K 是列表的数量。例如,给定列表 [1, 2, 3] 和 [4,
我试图理解这些语法结构之间的语义差异。 if ((i% k) == (l % k) == 0) 和 if ((i % k) == 0 && (l % k) == 0) 最佳答案 您的特定表达式((i
我有时会使用一维数组: A = np.array([1, 2, 3, 4]) 或 2D 阵列(使用 scipy.io.wavfile 读取单声道或立体声信号): A = np.array([[1, 2
在文档聚类过程中,作为数据预处理步骤,我首先应用奇异向量分解得到U、S和Vt 然后通过选择适当数量的特征值,我截断了 Vt,这让我从阅读的内容中得到了很好的文档-文档相关性 here .现在我正在对矩
我问的是关于 Top K 算法的问题。我认为 O(n + k log n) 应该更快,因为……例如,如果您尝试插入 k = 300 和 n = 100000000,我们可以看到 O(n + k log
这个问题与另一个问题R:sample()密切相关。 。我想在 R 中找到一种方法来列出 k 个数字的所有排列,总和为 k,其中每个数字都是从 0:k 中选择的。如果k=7,我可以从0,1,...,7中
我目前正在评估基于隐式反馈的推荐系统。我对排名任务的评估指标有点困惑。具体来说,我希望通过精确度和召回率来进行评估。 Precision@k has the advantage of not requ
我在 Python 中工作,需要找到一种算法来生成所有可能的 n 维 k,k,...,k 数组,每个数组都沿轴有一行 1。因此,该函数接受两个数字 - n 和 k,并且应该返回一个数组列表,其中包含沿
我们有 N 对。每对包含两个数字。我们必须找到最大数 K,这样如果我们从给定的 N 对中取 J (1 2,如果我们选择三对 (1,2),我们只有两个不同的数字,即 1 和 2。 从一个开始检查每个可能
鉴于以下问题,我不能完全确定我当前的解决方案: 问题: 给定一个包含 n 元素的最大堆,它存储在数组 A 中,是否可以打印所有最大的 K 元素在 O(K*log(K)) 中? 我的回答: 是的,是的,
我明白了: val vector: RDD[(String, Array[String])] = [("a", {v1,v2,..}),("b", {u1,u2,..})] 想转换成: RDD[(St
我有 X 个正数,索引为 x_i。每个 x_i 需要进入 K 组之一(其中 K 是预先确定的)。令 S_j 为 K_j 中所有 x_i 的总和。我需要分配所有 x_i 以使所有 S_j 的方差最小化。
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我正在研究寻找原始数的算法,看到下面的语句,我不明白为什么。 while (k*k <= n) 优于 while (k <= Math.sqrt(n)) 是因为函数调用吗?该调用函数使用更多资源。 更
我想找到一种尽可能快的方法来将两个小 bool 矩阵相乘,其中小意味着 8x8、9x9 ... 16x16。这个例程会被大量使用,所以需要非常高效,所以请不要建议直截了当的解决方案应该足够快。 对于
有没有一种惯用的方法来获取 Set和 Function ,并获得 Map实时取景? (即 Map 由 Set 和 Function 组合支持,例如,如果将元素添加到 Set ,则相应的条目也存在于 M
这个问题在这里已经有了答案: Can a local variable's memory be accessed outside its scope? (20 个答案) returning addr
给定一个矩阵:- k = [1 2 3 ; 4 5 6 ; 7 8 NaN]; 如果我想用 0 替换一个数字,比如 2,我可以使用这个:k(k==2) =
我是一名优秀的程序员,十分优秀!