洛谷 P3317 [SDOI2014]重建

除去不选的边要为答案做出 \(1 - g\) 的贡献,这道题完全就是个矩阵-树板子了。考虑怎么化掉 \(1 - g\)
一条边由不选转为选,其贡献由 \(1 - g\) 变为了 \(g\),所以边权为 \(\frac g {1 - g}\)

#include <cstdio>
#include <cmath>
#include <algorithm>

const int MAXN = 59;
const double EPS = 1e-12;

double a[MAXN][MAXN], s = 1.0;

double det(int n){
	double res = 1.0;
	for(int i = 1; i <= n; ++i){
		int r = i;
		for(int j = i + 1; j <= n; ++j)
			if(std::fabs(a[r][i]) < std::fabs(a[j][i]))
				r = j;
		if(i ^ r){
			std::swap(a[i], a[r]);
			res = -res;
		}
		if(std::fabs(a[i][i]) < EPS)
			return 0;
		for(int j = i + 1; j <= n; ++j){
			double d = a[j][i] / a[i][i];
			for(int k = i; k <= n; ++k)
				a[j][k] -= a[i][k] * d;
		}
		res *= a[i][i];
	}
	return res;
}

double g[MAXN][MAXN];
int n;

inline void insert(int u, int v, double m){
	a[u][u] += m, a[v][v] += m;
	a[u][v] -= m, a[v][u] -= m;
}

int main(){
	std::scanf("%d", &n);
	for(int i = 1; i <= n; ++i)
		for(int j = 1; j <= n; ++j)
			std::scanf("%lf", &g[i][j]);
	for(int i = 1; i <= n; ++i)
		for(int j = i + 1; j <= n; ++j)
			insert(i, j, g[i][j] / (1.0 - g[i][j] + EPS)), s *= (1.0 - g[i][j] + EPS);
	std::printf("%.12f\n", s * det(n - 1));
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/natsuka/p/12687244.html
今日推荐