1 /*
2
3 [转]http://hi.baidu.com/accplaystation/blog/item/51417bdca982bea4cc116660.html
4
5 这道题据说有两种思路:
6
7 1——将总的方案数减掉所有不连通的方案。
8
9 总的方案数是2^(C(n,2)),不连通的方案数可以如下考虑:
10
11 当和点1连通的点数共有k个时,方案数为C(n-1,k)*F(k+1),其他n-k-1各点间任意连边即可,
方案数为2^(C(n-k-1,2)),所以这样的方案数共有C(n-1,k)*F(k+1)* 2^(C(n-k-1,2))种。
12
13 因此可以得到递推公式:
14
15 F(n)= 2^(C(n,2))-Sum(C(n-1,k)*F(k+1)* 2^(C(n-k-1,2)) | 0<=k<n)
16
17 这种思路的优点在于简单明了,但是缺点在于编程复杂,要算高精度的加、减、乘,2的幂也非常大,
故某人忽略之……
18
19 2——直接求连通的方案数。
20
21 考虑拿掉点1时点2的情况,设此时点2所在连通块共k各点,这k个点以及剩下的n-k个点分别处在一个连通块中,
其方案数为F(k)*F(n-k),点2需在除去点1和2的点中取k-1个点构成连通块,故方案数为C(n-2,k-1),
而这总共k个点与剩下除去点1的n-k-1个点必须通过点1才能连通,即这k个点与点1至少有1条边连通,
这样的方案数为2^k-1,故这样的情况总共有F(k)*F(n-k)* C(n-2,k-1)*( 2^k-1)种。
22
23 因此可得递推公式为:
24
25 F(n)=Sum(F(k)*F(n-k)* C(n-2,k-1)*( 2^k-1) | 1<=k<n)。
26
27 这种思路虽然理解比较困难,也不知道我解释清楚了没有,汗……但是却极大的减轻了编程的负担,只需要高精度加和乘,
2的幂只到50 。我的程序就是靠思路二解决的。
28
29 确定了思路,剩下的就是高精度的问题了,当然对于Java者,飘过之……
30
31 核心代码:
32 */
33 void calc(int n)
34
35 {
36
37 int k;
38
39 ans[n].len=1;
40
41 memset(ans[n].num,0,sizeof(ans[n].num));
42
43 Large tmpa,tmpb,tmpc,tmpd;
44
45 for (k=1;k<n;++k)
46
47 {
48
49 Lcopy(ans[n],tmpa);
50
51 Lmul(ans[k],ans[n-k],tmpb);
52
53 Lmul(tmpb,C[n-2][k-1],tmpc);
54
55 Lmulone(tmpc,ptwo[k]-1,tmpd);
56
57 Ladd(tmpa,tmpd,ans[n]);
58
59 }
60
61 }