//变元矩阵树定理: 边矩阵Aij表示边权Eij,Aii=0 度数矩阵D只有Dii有值 Dii表示点i的邻接点边权和
//基尔霍夫矩阵K=D-A 那么我们有|K|= 所有生成树的边权的积的和= sum{Tree} mul{e属于Tree}val(e)
//O(n^3) P3317题意:无向图给出每条边的概率,问最后形成n-1条边的树的概率
//ans=sum{Tree}( mul{e属于Tree}p(e)*mul{e不属于Tree }(1-p(e)) )
//ans=sum{Tree}( mul{e属于Tree}p(e)*mul{e属于边权全集}(1-p(e))/mul{e属于Tree}(1-p(e)) )
//ans=mul{e属于边权全集}(1-p(e))* sum{Tree}( mul{e属于Tree}p(e)/mul{e属于Tree}(1-p(e)))
//ans=mul{e属于边权全集}(1-p(e))* sum{Tree}( mul{e属于Tree}p(e)/(1-p(e)) )
//所以令边权pe=pe/(1-pe)即可 套用上面的变元矩阵树定理求解
#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;i++)
using namespace std;
const double eps=1e-8;
double p[205][205];
namespace Gauss{
double K[205][205];
double det(int n) {//行列式n的值
int tr=0;
rep(i,1,n) {
int p=i;
rep(j,i+1,n)if (fabs(K[j][i]) > fabs(K[p][i])) p = j;//找到最大的行p
if (p!=i) rep(j,i,n) swap(K[i][j],K[p][j]);//然后交换
rep(j,i+1,n) {//将第i+1~n行的第i个置为0
double tmp = K[j][i] / K[i][i];
rep(k,i,n) K[j][k] -= K[i][k] * tmp;
}
}
double ans = 1.0;
rep(i,1,n) ans *= K[i][i];
return ans;
}
}
int main(){
int n;double ans=1.0;cin>>n;
using namespace Gauss;
rep(i,1,n){
rep(j,1,n){
cin>>K[i][j];
if(K[i][j]<eps)K[i][j]=eps;
if(1.0-K[i][j]<eps)K[i][j]=1.0-eps;
if(j>i)ans*=(1.0-K[i][j]);
K[i][j]=K[i][j]/(1.0-K[i][j]);
}
}
rep(i,1,n){
K[i][i]=0;
rep(j,1,n){
if(i!=j){
K[i][i]+=K[i][j];
K[i][j]=-K[i][j];
}
}
}
cout<<ans*det(n-1);//n-1阶余子式
system("pause");
}