problem
solution
d p ( i ) : dp(i): dp(i): 当恰好加入第 i i i 小边时候,所有点联通的方案数。
则 a n s = ∑ i d p i ( m i ) i m + 1 ans=\sum_i \frac{dp_i}{\binom mi}\frac{i}{m+1} ans=∑i(im)dpim+1i 。
重点是如何计算出 d p ( i ) dp(i) dp(i)。
这个恰好的限制不好搞。加第 i i i 小的边之前不能提前联通,加后一定要联通。
转化一下, d p ( i ) = dp(i)= dp(i)= 加之前不连通的方案数 − - − 加之后不连通的方案数。
记 f ( s , i ) : s f(s,i):s f(s,i):s 点集中的点之间连了 i i i 条边后 s s s 中的点仍然不连通的方案数。
记 g ( s , i ) : s g(s,i):s g(s,i):s 点集中的点之间连了 i i i 条边后 s s s 中的点联通的方案数。
显然 f ( s , i ) + g ( s , i ) = ( c n t ( s ) i ) f(s,i)+g(s,i)=\binom{cnt(s)}{i} f(s,i)+g(s,i)=(icnt(s)),其中 c n t ( s ) : cnt(s): cnt(s): 点集 s s s 中的点之间的边数。
转移枚举
s
s
s 的子集
t
t
t,满足
s
&
(
−
s
)
s\&(-s)
s&(−s),即
s
s
s 中最小元素点也在
t
t
t 集合内。
f
(
s
,
i
)
=
∑
(
s
&
−
s
)
∈
t
⊂
s
∑
j
=
0
i
g
(
t
,
j
)
(
s
⊕
t
i
−
j
)
f(s,i)=\sum_{(s\&-s)\in t\subset s}\sum_{j=0}^ig(t,j)\binom{s\oplus t}{i-j}
f(s,i)=(s&−s)∈t⊂s∑j=0∑ig(t,j)(i−js⊕t)
这种转移相当于以
s
s
s 中最小元素点为参考,其所在的联通块为
t
t
t,其余看作不连通,且
(
s
⊕
t
i
−
j
)
\binom{s\oplus t}{i-j}
(i−js⊕t) 任意选的边连出来的集合一定不与
t
t
t 有边相连。这样就不会算重了。
最后 d p i = f ( { 1 , 2 , . . . , n } , i − 1 ) − f ( { 1 , 2 , . . . , n } , i ) dp_i=f(\{1,2,...,n\},i-1)-f(\{1,2,...,n\},i) dpi=f({1,2,...,n},i−1)−f({1,2,...,n},i)。
在代码实现中统计答案略有不同,我是将这个式子稍微展开了一下。
a
n
s
=
∑
i
=
1
m
i
m
+
1
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
−
1
)
−
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
(
m
i
)
ans=\sum_{i=1}^m\frac{i}{m+1}\frac{f(\{1,2,...,n\},i-1)-f(\{1,2,...,n\},i)}{\binom mi}
ans=i=1∑mm+1i(im)f({1,2,...,n},i−1)−f({1,2,...,n},i)
考虑相邻两位:
i
m
+
1
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
−
1
)
−
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
(
m
i
)
i
+
1
m
+
1
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
−
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
+
1
)
(
m
i
+
1
)
\frac{i}{m+1}\frac{f(\{1,2,...,n\},i-1)-f(\{1,2,...,n\},i)}{\binom mi}\\ \frac{i+1}{m+1}\frac{f(\{1,2,...,n\},i)-f(\{1,2,...,n\},i+1)}{\binom m{i+1}}
m+1i(im)f({1,2,...,n},i−1)−f({1,2,...,n},i)m+1i+1(i+1m)f({1,2,...,n},i)−f({1,2,...,n},i+1)
将
1
m
+
1
\frac{1}{m+1}
m+11 提出来,发现
i
∗
−
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
i*-f(\{1,2,...,n\},i)
i∗−f({1,2,...,n},i) 且
(
i
+
1
)
∗
+
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
(i+1)*+f(\{1,2,...,n\},i)
(i+1)∗+f({1,2,...,n},i),相加其实就是加入了一次
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
f(\{1,2,...,n\},i)
f({1,2,...,n},i)。
而 f ( { 1 , 2 , . . . , n } , m ) = 0 f(\{1,2,...,n\},m)=0 f({1,2,...,n},m)=0,不可能所有边都加完了还不联通。
所以,有:
a
n
s
=
1
m
+
1
∑
i
=
0
m
f
(
{
1
,
2
,
.
.
.
,
n
}
,
i
)
(
m
i
)
ans=\frac{1}{m+1}\sum_{i=0}^m\frac{f(\{1,2,...,n\},i)}{\binom mi}
ans=m+11i=0∑m(im)f({1,2,...,n},i)
code
#include <bits/stdc++.h>
using namespace std;
#define double long double
#define int long long
int n, m;
int cnt[1 << 10];
double c[50][50];
int f[1 << 10][50], g[1 << 10][50];
struct node { int u, v; }E[50];
signed main() {
scanf( "%lld %lld", &n, &m );
for( int i = 1;i <= m;i ++ )
scanf( "%lld %lld", &E[i].u, &E[i].v );
for( int s = 0;s < (1 << n);s ++ )
for( int i = 1;i <= m;i ++ )
if( (s >> E[i].u - 1 & 1) and (s >> E[i].v - 1 & 1) )
cnt[s] ++;
for( int i = 0;i <= m;i ++ ) {
c[i][0] = c[i][i] = 1;
for( int j = 1;j < i;j ++ )
c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
}
for( int s = 0;s < (1 << n);s ++ )
for( int i = 0;i <= cnt[s];i ++ ) {
for( int t = s;t;t = (t - 1) & s )
if( t & (s & -s) )
for( int j = 0;j <= min( cnt[t], i );j ++ )
f[s][i] += g[t][j] * c[cnt[s ^ t]][i - j];
g[s][i] = c[cnt[s]][i] - f[s][i];
}
double ans = 0;
for( int i = 0;i <= m;i ++ )
ans += 1.0 / (m + 1) * f[(1 << n) - 1][i] / c[m][i];
printf( "%Lf\n", ans );
return 0;
}