bzoj4031 [HEOI2015]小Z的房间

原创 2017年01月03日 23:15:57

【题意】

给定一个n*m的网格图,其中有一些坏点。求不包含坏点的生成树个数,答案对10^9取模。

【数据范围】

n<=9,m<=9

【思路】

本题有两种方法:

[方法一]matrix-tree定理

kirchhoff矩阵=度数矩阵-邻接矩阵

n阶矩阵的任意一个(n-1)阶主子式=这个矩阵去掉第i行第i列,i任意

matrix-tree定理:生成树个数=kirchhoff矩阵任意一个(n-1)阶主子式行列式的绝对值

求解矩阵行列式:

行列式的2个性质:

1.将矩阵任意一行的数值*k加到矩阵另一行上,矩阵行列式的值不变,列同理

2.交换两行,行列式取相反数,列同理

故我们采用类似高斯消元的方法:

对于每一列的元素,根据上面2个性质进行“消元”,将这一列上除当前第一个数外的其余所有数均消成0,然后矩阵规模-1,循环直到矩阵规模为1*1即可

故求解n*n矩阵的行列式,时间复杂度为O(n^3)

本题由于模数不是质数,故使用辗转相除进行消元

[方法二]插头dp

本题不同于一般的插头dp,由于求解生成树个数,故状态表示对应格点的连通性,使用最小表示法记录状态

【时间复杂度】

[方法一]O(n^6)

[方法二]O(状态数*n^2)

【方法一】

//matrix-tree定理+辗转相除消元 
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 90
#define mod 1000000000
#define ll long long
using namespace std;
 
const int dx[4]={-1, 0, 0, 1};
const int dy[4]={0, -1, 1, 0};
int n, m, now, pos[N][N], a[N][N], x, y;
char S[20];
 
int get_hls(int n){
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)a[i][j]=(a[i][j]+mod)%mod;
    int ans=1, ff=1, A, B, t;
    for(int i=1; i<=n; i++){
        for(int j=i+1; j<=n; j++){
            A=a[i][i]; B=a[j][i];
            while(B){
                t=A/B; A=A%B; swap(A, B);
                for(int k=i; k<=n; k++)a[i][k]=(a[i][k]-(ll)t*a[j][k]%mod+mod)%mod;
                for(int k=i; k<=n; k++)swap(a[i][k], a[j][k]);
                ff^=1;
            }
        }
        if(!a[i][i])return 0;
        ans=(ll)ans*a[i][i]%mod;
    }
     
    if(!ff)return (mod-ans)%mod; else return ans;
}
 
int main(){
    scanf("%d%d", &n, &m); now=0;
    memset(pos, 0, sizeof(pos));
    for(int i=1; i<=n; i++){
        scanf("%s", S+1);
        for(int j=1; j<=m; j++)
            if(S[j]=='.')pos[i][j]=++now;
    }
    memset(a, 0, sizeof(a));
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)if(pos[i][j]){
            for(int k=0; k<=3; k++){
                x=i+dx[k]; y=j+dy[k];
                if(x>=1&&x<=n&&y>=1&&y<=m&&pos[x][y]){
                    a[pos[i][j]][pos[i][j]]++;
                    a[pos[i][j]][pos[x][y]]--;
                }
            }
        }
    printf("%d", get_hls(now-1));
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

BZOJ 4031: [HEOI2015]小Z的房间

题目大意:求生成树个数做法:用matrix-tree定理。对于一个图,求出它的拉普拉斯算子c c[i][j]=d[i][j]-a[i][j],d为度数矩阵,当i=j时为i的度数,否则为0,a为邻接矩...

BZOJ 4031 HEOI2015 小Z的房间 Matrix-Tree定理

题目大意:给定一张地图,求生成树个数 Matrix-Tree定理直接上 不过模数是10910^9,不能直接求逆元 因此消元的时候辗转相除一下就好了#include #include #inc...
  • PoPoQQQ
  • PoPoQQQ
  • 2015年04月30日 18:09
  • 2052

[BZOJ4031][HEOI2015]小Z的房间(矩阵树定理+高斯消元)

晚上回家收拾收拾东西!虽然ATP的箱子里现在只有半箱零食。。
  • FromATP
  • FromATP
  • 2017年04月06日 16:57
  • 514

【HEOI2015】【BZOJ4031】小Z的房间

Description你突然有了一个大房子,房子里面有一些房间。事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子。在一开始的时候,相邻的格子之间都有墙隔着。你...

bzoj4031【HEOI2015】小Z的房间

Matrix-Tree定理+高斯消元求行列式

BZOJ 4031([HEOI2015]小Z的房间-矩阵树定理+辗转相除)

矩阵树定理,注意gauss消元辗转相除的写法#include using namespace std; #define For(i,n) for(int i=1;i...

【bzoj4031】 HEOI2015小Z的房间 矩阵树定理

第一次做矩阵树定理的题,其实就是记了个结论也没太看证明,然后学了学怎么用高斯消元求行列式,整数消元还真别扭,要用辗转相除,然后要注意取模的问题,一开始以为hzwer写麻烦了,后来想了想不加外面那句话会...

【HEOI2015】bzoj4031 小z的房间

矩阵树定理
  • sdfzyhx
  • sdfzyhx
  • 2017年03月09日 07:46
  • 143

BZOJ 4031: [HEOI2015]小Z的房间 矩阵树定理

4031: [HEOI2015]小Z的房间 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 1193  Solved: 587 [Submit][St...

BZOJ4031——HEOI小z的房间

题意:求某网格图生成树个数,对1e9取模 题解:题目是裸的Matrix-Tree定理,这不是我要说的重点,重点是对于这个取模的处理。 因为这不是个质数,所以不能直接乘逆元来当除法用,直接高斯消元肯...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:bzoj4031 [HEOI2015]小Z的房间
举报原因:
原因补充:

(最多只允许输入30个字)