• 走进矩阵树定理--「CodePlus 2017 12 月赛」白金元首与独舞


    n,m<=200,n*m的方阵,有ULRD表示在这个格子时下一步要走到哪里,有一些待决策的格子用.表示,可以填ULRD任意一个,问有多少种填法使得从每个格子出发都能走出这个方阵,答案取模。保证未确定的格子<=300。

    。。。一脸懵逼地写了原本30实际20的暴力然后跪着啃了下论文

    然而什么都没啃懂不如结论记下来:

    首先矩阵行列式的定义:一个n*n的矩阵,行列式值为$sum_{b是n的一个排列} ( (-1)^{b的逆序对数} * prod_{i=1}^{n} A_{i,b_i})$

    矩阵A行列式的性质:

    |A|=|A的转置|

    |AB|=|A||B|

    |A|+|B|=|A和B的某一行加起来其他不变的矩阵|

    交换两行得B,|B|=-|A|,因为每次计算一个排列时逆序对数都相差1。

    A的某行乘个x得B,|B|=x|A|。

    A的某行乘某个数加到另一行上得B,|B|=|A|。由第三条可得。

    每行每列和为0的矩阵行列式为0。

    由四五六条可用高斯消元计算行列式。

    基尔霍夫矩阵:

    无向图:矩阵对角线上是度数,其他如果对应边存在就是-1,不然就是0。

    有向图:矩阵对角线上是入度,其他如果对应边存在就是-1,不然就是0。

    矩阵树定理:一个无向图的基尔霍夫矩阵的任意一个n-1阶的子矩阵,即删掉了第i行和第i列,的行列式是这个图的生成树个数。

    一个有向图以点i为根的生成树个数是基尔霍夫矩阵去掉第i行和第i列剩下的矩阵的行列式。

    如果图为多图,作如下修改:

    当$i eq j$而有重边时,把邻接矩阵的1改成$i$,$j$间的边数;

    当$i = j$而有自环时,自环不可能出现在生成树中,统计度数时记得忽略之。

    嗯然后就是这道题。

    首先,如果在外界虚拟一个节点,把所有指出去的格子都指向它,把所有确定格子向指向的点连边,可得一个有向图。

    然后,待确定的点向四个方向都连边,求这个图以外界点为根的反向的树形图即可。为什么呢,首先确定的格子的边一定会选到,因为每个格子只有一条出边,不然他就和其他点断掉了;其次那些待确定的格子为了形成树,只会在四个方向里选一个。

    嗯这样只能拿50分。

    可以发现那些已经确定的点是多余的,可以缩掉。也就是给所有待确定格子编号,外界点编号0,然后预处理他往上下左右走能遇到的第一个有编号的格子,朝他们连边即可。

    然后就大功告成了。

      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<algorithm>
      4 #include<stdlib.h>
      5 //#include<queue>
      6 #include<math.h>
      7 //#include<time.h>
      8 //#include<iostream>
      9 using namespace std;
     10 
     11 int n,m,K,T;
     12 const int mod=1e9+7;
     13 #define maxn 311
     14 int pos[maxn][maxn],who[maxn][maxn],place[maxn][4]; char mp[maxn][maxn];
     15 
     16 int powmod(int a,int b)
     17 {
     18     int ans=1;
     19     while (b)
     20     {
     21         if (b&1) ans=1ll*ans*a%mod;
     22         a=1ll*a*a%mod;
     23         b>>=1;
     24     }
     25     return ans;
     26 }
     27 
     28 struct Mat
     29 {
     30     int num[maxn][maxn];
     31     void clear() {memset(num,0,sizeof(num));}
     32 }mat;
     33 int gauss()
     34 {
     35     int ans=1;
     36     for (int i=1;i<=K;i++)
     37     {
     38         int id=i;
     39         for (int j=i+1;j<=K;j++) if (fabs(mat.num[j][i])>fabs(mat.num[id][i])) id=j;
     40         if (id!=i)
     41         {
     42             ans=1ll*ans*(mod-1)%mod;
     43             for (int j=i;j<=K;j++) {int t=mat.num[i][j]; mat.num[i][j]=mat.num[id][j]; mat.num[id][j]=t;}
     44         }
     45         int tmp=powmod(mat.num[i][i],mod-2);
     46         for (int j=i+1;j<=K;j++)
     47             for (int k=K;k>=i;k--)
     48                 mat.num[j][k]-=mat.num[i][k]*1ll*mat.num[j][i]%mod*tmp%mod,
     49                 mat.num[j][k]+=mat.num[j][k]<0?mod:0;
     50     }
     51     for (int i=1;i<=K;i++) ans=1ll*ans*mat.num[i][i]%mod;
     52     return ans;
     53 }
     54 
     55 int vis[maxn][maxn],Time; bool die;
     56 void dfs(int x,int y)
     57 {
     58     if (mp[x][y]=='.') return;
     59     if (vis[x][y])
     60     {
     61         if (pos[x][y]==-1) die=1;
     62         return;
     63     }
     64     vis[x][y]=1;
     65     int tx=x,ty=y;
     66     if (mp[x][y]=='U') x--;
     67     else if (mp[x][y]=='D') x++;
     68     else if (mp[x][y]=='L') y--;
     69     else if (mp[x][y]=='R') y++;
     70     if (x<1 || x>n || y<1 || y>m) pos[tx][ty]=0;
     71     else pos[tx][ty]=-1,dfs(x,y),pos[tx][ty]=pos[x][y];
     72 }
     73 int check(int x,int y)
     74 {
     75     if (x<1 || x>n || y<1 || y>m) return 0;
     76     return pos[x][y];
     77 }
     78 
     79 int main()
     80 {
     81     scanf("%d",&T);
     82 while (T--)
     83 {
     84     scanf("%d%d",&n,&m); K=0; Time=0; die=0;
     85     memset(vis,0,sizeof(vis));
     86     memset(pos,0,sizeof(pos));
     87     for (int i=1;i<=n;i++) scanf("%s",mp[i]+1);
     88     for (int i=1;i<=n;i++)
     89         for (int j=1;j<=m;j++)
     90             if (mp[i][j]=='.') pos[i][j]=++K;
     91     for (int i=1;i<=n;i++)
     92         for (int j=1;j<=m;j++)
     93             if (mp[i][j]!='.') dfs(i,j);
     94     if (die) {puts("0"); continue;}
     95     
     96     for (int i=1;i<=n;i++)
     97         for (int j=1;j<=m;j++)
     98             if (mp[i][j]=='.')
     99             {
    100                 int nx=i,ny=j,now=pos[i][j];
    101                 nx++; place[now][0]=check(nx,ny); nx--;
    102                 nx--; place[now][1]=check(nx,ny); nx++;
    103                 ny++; place[now][2]=check(nx,ny); ny--;
    104                 ny--; place[now][3]=check(nx,ny); ny++;
    105             }
    106     mat.clear();
    107     for (int i=1;i<=K;i++)
    108     {
    109         for (int j=0;j<4;j++) mat.num[place[i][j]][i]--;
    110         mat.num[i][i]+=4;
    111     }
    112     for (int i=1;i<=K;i++)
    113         for (int j=1;j<=K;j++)
    114             if (mat.num[i][j]<0) mat.num[i][j]+=mod;
    115     printf("%d
    ",gauss());
    116 }
    117     return 0;
    118 }
    View Code
  • 相关阅读:
    Django基础命令
    ubuntu中python项目独立的虚拟环境
    Springboot项目的小问题
    redis
    ubuntu系统根目录下各个目录用途说明
    SpringBoot 在IDEA中实现热部署
    SpringBoot访问不到webapp下的内容
    httpServeltRequest和Model传值的区别
    map的输出
    主流框架排名
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8126582.html
Copyright © 2020-2023  润新知