题解:P7105 「C.E.L.U-01」门禁
P7105 「C.E.L.U-01」门禁
meet in the middle 折半搜索练习。参考题解
\(O(3^n)\) 做法。
设 \(f_S\) 为 \(S\) 中点集构成一个连通块的概率。
则有套路容斥:考虑这个点集不是连通块时,枚举点集中编号最小的那个点所在的连通块,要求这个连通块自己连通,并且和剩余的点之间没有边。
可以得到转移式:
\[f_S=1-\sum_{T\subset S}f_TF(S\backslash T,T)
\]
其中 \(F(S,T)\) 是 \(S\) 与 \(T\) 之间没有边的概率。\(T\) 包含编号最小的那个点。
暴力计算将得到一个 \(O(3^nn^2)\) 的做法。
为了优化掉后面那坨东西,考虑能不能预处理掉。考虑折半:预处理出 4 个数组 \(s_{0/1,0/1,x,y}\),\(x\) 和 \(y\) 分别对应的点集区间是:
- \([0,n/2)\) 和 \([0,n/2)\)
- \([0,n/2)\) 和 \([n/2,n)\)
- \([n/2,n)\) 和 \([0,n/2)\)
- \([n/2,n)\) 和 \([n/2,n)\)
数组记录点集 \(x\) 和点集 \(y\) 之间不连通的概率。
这样暴力预处理这 4 个数组的时间是 \(O(2^nn^2)\),同时可以通过拆分集合,把对应的 \(s\) 相乘来 \(O(1)\) 查询 \(F(S,T)\)。
如此继续暴力执行 DP 即可做到 \(O(3^n)\),而且常数很小。这一做法可以推广到类似的状压连通块的题目,且均可以做到 \(O(2^nn^2+3^n)\)。
实现有一些细节:处理 s 的时候如果是减去一个下标状压的,注意 \(s\) 数组的 \(x & y\) 不一定为 \(0\),因为 \(x\) 和 \(y\) 即使一样也不一定对应的是同一个点集,原点集需要给所有点减去一个下标,而减去的下标不一定相同。
点击查看代码
#include <bits/stdc++.h>
typedef long double lb;
using namespace std;
const int N2 = 1000010,N = 20;
int n,m;
lb p[N][N],g[2][2][1010][1010],f[N2];
void init(int a,int b){
int x = 0,y = 0,ux = m - 1,uy = m - 1;
if(a == 1)x = m,ux = n - 1;
if(b == 1)y = m,uy = n - 1;
for(int i = 0; i < (1 << (ux - x + 1)); i++){
for(int j = 0; j < (1 << (uy - y + 1)); j++){
g[a][b][i][j] = 1;
for(int ia = x; ia <= ux; ia++){
if(!(1 & (i >> (ia - x))))continue;
for(int ib = y; ib <= uy; ib++){
if(!(1 & (j >> (ib - y))))continue;
g[a][b][i][j] *= (1.0 - p[ia + 1][ib + 1]);
}
}
}
}
}
lb calc(int x,int y){
int ax = x & ((1 << m) - 1),bx = (x >> m);
int ay = y & ((1 << m) - 1),by = (y >> m);
return g[0][0][ax][ay] * g[0][1][ax][by] * g[1][0][bx][ay] * g[1][1][bx][by];
}
int main(){
scanf("%d",&n);
m = n / 2;
for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)scanf("%Lf",&p[i][j]);
init(0,0),init(0,1),init(1,0),init(1,1);
f[0] = 1;
for(int i = 0; i < (1 << n); i++){
f[i] = 1.0;
int k = i ^ (i & (-i));
for(int j = k; j; j = (j - 1) & k){
f[i] -= f[i ^ j] * calc(i ^ j,j);
}
}
lb ans = 0;
for(int i = 1; i < (1 << n); i++)ans += f[i] * calc(i,(1 << n) - 1 - i);
printf("%.6Lf",ans);
return 0;
}

浙公网安备 33010602011771号