SHCPC2022 I 题解
爱讨论!
SHCPC2022 I
关注到这个题目本质上等价于下面这个题目:
每次随机选择两个点,将其连边,当出现以下情况时就停止连边:
- 某个点度数
>2 - 重边
- 自环
求期望步数。
这个问题里,我们要考虑的就是环的情况。我们考虑仅有点数
-
两个孤立点:
当
i>1 时,有f_{i,j,k}\leftarrow f_{i-1,j+1,k} ,对应概率为p = \frac{\binom{n}{2}}{n^2} -
一个孤立点和一条短链:
考虑拿孤立点和短链的一端成长链,当
i>0,j>0 时,有f_{i,j,k}\leftarrow f_{i-1,j-1,k+1} ,对应概率为p = \frac{2ij}{n^2} -
一个孤立点和一条长链:
考虑拿孤立点和长链的一端成长链,当
i>0,k>0 时,有f_{i,j,k}\leftarrow f_{i-1,j,k} ,对应概率为p = \frac{2ik}{n^2} -
一个短链和另一条短链:
考虑拿短链一端和另一条短链的一端成长链,当
j>1 时,有f_{i,j,k}\leftarrow f_{i,j-2,k+1} ,对应概率为p = \frac{\binom{j}{2}*2*2*2}{n^2} 注意这里顺序可以颠倒所以多一个 -
一个短链和一条长链:
考虑拿短链两端和长的一端成长链,当
j>0,k>0 时,有f_{i,j,k}\leftarrow f_{i,j-1,k} ,对应概率为p = \frac{2*2*2jk}{n^2} -
一个长链和另一条长链:
拿长链一端和另一条长链的一端成长链,当
k>1 时,有f_{i,j,k}\leftarrow f_{i,j,k-1} ,对应概率为p = \frac{\binom{k}{2}*2*2*2}{n^2} 注意这里顺序可以颠倒所以多一个 -
长链自己成环
这个就直接当
k>0 时有f_{i,j,k} = f_{i,j,k-1} ,对应概率p = \frac{2k}{n}
转移方程是
/*
Undo the destiny.
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
const int N = 210;
double f[N][N][N];
double n;
double dp(int i,int j,int k) {
// cerr << i << " " << j << " " << k << ":" << f[i][j][k]<< "\n";
if (f[i][j][k] != -1) return f[i][j][k];
if ((i == 1 && j == 0 && k == 0)) return f[i][j][k] = 0;
if ((i == 0 && j == 1 && k == 0)) return f[i][j][k] = 0;
if ((i == 0 && j == 0 && k == 0)) return f[i][j][k] = 0;
double ans = 1;
double sump = 0,nowp = 0;
if (i >= 2) {
nowp = 1.0 * (i-1)*i / (n*n);
ans += dp(i-2,j+1,k) * nowp;
sump += nowp;
}
if (i >= 1 && j >= 1) {
nowp = 1.0*i*j*2*2 / (n*n);
ans += dp(i-1,j-1,k+1) * nowp;
sump += nowp;
}
if (i >= 1 && k >= 1) {
nowp = 4.0*i*k / (n*n);
ans += dp(i-1,j,k) * nowp;
sump += nowp;
}
if (j >= 2) {
nowp = 4.0*j*(j-1) / (n*n);
ans += dp(i,j-2,k+1) * nowp;
sump += nowp;
}
if (j >= 1 && k >= 1) {
nowp = 8.0*j*k / (n*n);
ans += dp(i,j-1,k) * nowp;
sump += nowp;
}
if (k >= 2) {
nowp = 4.0*k*(k-1) / (n*n);
ans += dp(i,j,k-1) * nowp;
sump += nowp;
}
if (k >= 1) {
nowp = 2.0*k / (n*n);
ans += dp(i,j,k-1) * nowp;
sump += nowp;
}
if (sump > 0) ans /= sump;
else ans = 0;
// cerr << i << " " << j << " " << k << ":" << ans <<","<<sump<< "\n";
return f[i][j][k] = ans;
}
void solve() {
cin >> n;
for (int i = 0;i <= (int)n;++i) {
for (int j = 0;j <= (int)n;++j) {
for (int k = 0;k <= (int)n;++k) {
f[i][j][k] = -1;
}
}
}
cout << fixed << setprecision(10) << dp(n,0,0);
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T = 1;//cin >> T;
while (T--) solve();
return 0;
}
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。