[BZOJ4031][HEOI2015]小Z的房间(矩阵树定理+高斯消元)
2017-04-06 16:57
393 查看
=== ===
这里放传送门=== ===
题解
没错这就是个裸题矩阵树定理: 定义一个图的基尔霍夫矩阵为: A[i][j]=⎧⎩⎨d[i],−1,i=ji≠j 其中d[i]表示点i的度。 对于无向图来说,这个矩阵的任何一个n-1阶主子式的行列式的值就是这个图的不同生成树个数。
其中n-1阶主子式表示在矩阵中任意去掉标号相同的一行和一列以后剩下的子矩阵
但是这题模数实在是太 ! 恶 ! 心 ! 了!!!
ATP尝试了N多种方法包括什么最小公倍数乱搞。。
最后还是上网扒出了这种类似辗转相除的方法。。
原理在ATP写高斯消元的板子里有详细的解释[戳这里],ATP就懒得再打一遍了。。
代码
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const double eps=1e-8; const long long Mod=1e9; int n,m,mp[20][20],d[4][2]={{0,1},{1,0},{-1,0},{0,-1}},c[20][20],cnt; long long ans,A[110][110],mak; long long Abs(long long x){return (x<0)?-x:x;} long long gcd(long long a,long long b){ long long r=a%b; while (r!=0){a=b;b=r;r=a%b;} return b; } long long get_LCM(long long a,long long b){ return (a/gcd(a,b)*b); } void addedge(int x,int y){ int u,v,a,b; a=c[x][y]; for (int i=0;i<4;i++){ u=x+d[i][0];v=y+d[i][1]; if (c[u][v]!=0){ b=c[u][v];A[a][a]++;A[a][b]=-1; } } } /*void Gauss_Eli(int n){ int num; for (int i=1;i<=n;i++){ num=i; for (int j=i+1;j<=n;j++) if (Abs(A[j][i])>Abs(A[num][i])) num=j; for (int j=1;j<=n;j++) swap(A[i][j],A[num][j]); for (int j=i+1;j<=n;j++) if (A[j][i]!=0){ long long lcm=get_LCM(A[i][i],A[j][i]),ta,tb; ta=lcm/Abs(A[j][i]);tb=lcm/Abs(A[i][i]); if (A[j][i]*A[i][i]<0) tb=-tb; for (int k=1;k<=n;k++) A[j][k]=(ta*A[j][k]-tb*A[i][k])%Mod; } } }*/ void Gauss_Eli(int n){ int num; for (int i=1;i<=n;i++){ num=i; for (int j=i+1;j<=n;j++) if (Abs(A[j][i])>Abs(A[num][i])) num=j; if (num!=i) mak^=1; for (int j=1;j<=n;j++) swap(A[i][j],A[num][j]); for (int j=i+1;j<=n;j++) while (A[j][i]!=0){ long long tmp=A[j][i]/A[i][i]; for (int k=1;k<=n;k++)//做完一次操作以后A[j][i]相当于对A[i][i]取模了 A[j][k]=(A[j][k]+Mod-tmp*A[i][k]%Mod)%Mod; if (A[j][i]==0) break; mak^=1;//注意要维护取反标记,不能直接取绝对值 for (int k=1;k<=n;k++) swap(A[j][k],A[i][k]); } } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){ char s=getchar(); while (s!='.'&&s!='*') s=getchar(); if (s=='*') mp[i][j]=1; else c[i][j]=++cnt; } for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (mp[i][j]!=1) addedge(i,j); Gauss_Eli(cnt-1);ans=1; for (int i=1;i<cnt;i++) ans=(ans*A[i][i])%Mod; if (mak==1) ans=Mod-ans;//因为是取模运算所以一定要注意正负 ans=(ans+Mod)%Mod; printf("%I64d\n",ans); return 0; }
相关文章推荐
- BZOJ4031 [HEOI2015]小Z的房间 【矩阵树定理 + 高斯消元】
- [bzoj4031][HEOI2015]小Z的房间【矩阵树定理】【高斯消元】
- bzoj 4031: [HEOI2015]小Z的房间 (矩阵树定理+高斯消元)
- BZOJ 4031: [HEOI2015]小Z的房间 高斯消元 MartixTree定理 辗转相除法
- 【bzoj4031】[HEOI2015]小Z的房间 矩阵树定理
- BZOJ 4031: [HEOI2015]小Z的房间 [矩阵树定理 行列式取模]
- [bzoj4031][高斯消元][矩阵树]小Z的房间
- bzoj 4031: [HEOI2015]小Z的房间【矩阵树定理】
- BZOJ 4031: [HEOI2015]小Z的房间 Matrix-Tree定理+辗转相除法求行列式的值(高斯消元)
- bzoj 4031 [HEOI2015]小Z的房间 Matrix-tree定理
- BZOJ4031 [HEOI2015]小Z的房间
- 【BZOJ 4031】[HEOI2015]小Z的房间 基尔霍夫矩阵
- 【bzoj4031】[HEOI2015]小Z的房间 矩阵树定理模板
- BZOJ 4031 [HEOI2015]小Z的房间(Matrix-Tree定理)
- 【HEOI2015】【BZOJ4031】小Z的房间
- Bzoj4031 [HEOI2015]小Z的房间
- 【BZOJ】【P2467】【中山市选2010】【生成树】【题解】【矩阵树定理+高斯消元+打表】
- 【BZOJ4031】【HEOI2015】小Z的房间 [Matrix-Tree][行列式]
- [bzoj4031][HEOI2015]小Z的房间
- bzoj4031【HEOI2015】小Z的房间