//这道题是矩阵树定理中:给出有向图和其中一个点,求以这个点为根的生成外向树个数 /* 矩阵树定理:有向图有根树的情况 去掉所有自环,主对角线上第i行第i列是i这个点的出度,剩下的是邻接矩阵取相反数。 然后求的是删掉根节点所在行列式的余子式的行列式 */ #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <vector> #include <stack> #include <sstream> #include <map> #include <set> #include <queue> #include <stdlib.h> typedef long long ll; using namespace std; #define maxr 210 #define maxnode 40010 #define maxn 310 #define MOD 1000000007 #define LL long long int T, r, c; char Map[maxr][maxr]; //记录r行c列的字符 struct Graph //Graph有clear 和 AddEdge函数 { int n, m; int head[maxnode], nxt[maxnode], to[maxnode]; Graph() {} void clear() //一开始的m为0(0条边),head都是0 { m = 0; memset(head, 0, sizeof(head)); return ; } void AddEdge(int a, int b) //添加边 { //第++m条边, ++m; to[m] = b; //第m条边的to是b nxt[m] = head[a]; //第m条边的nxt是head[a] -> 之后head[a]=m head[a] = m; //a的head是m return ; } } G; int id(int i, int j) { return (i - 1) * c + j; } int vis[40010]; bool dfs(int u) { if(vis[u] == 2) return 0; if(vis[u]) return 1; vis[u] = 2; for(int e = G.head[u]; e; e = G.nxt[e]) { if(dfs(G.to[e])==0) { return 0; } } vis[u] = 1; return 1; } int pre[40010]; //祖先函数(pre) int find(int x) //寻找x的祖先(并查集) { if(x==pre[x]) return x; else return pre[x]=find(pre[x]); } int n, trid[40010]; int ID(int u) { if(trid[u]!=0) return trid[u]; else return trid[u]=++n; } int A[maxn][maxn], tA[maxn][maxn]; void MatAddEdge(int a, int b) { if(a == b) return ; tA[a][a]++; tA[a][b]--; return ; } void elim(int *a, int *b, int tar) { if(!b[tar]) return ; int rate = a[tar] / b[tar]; for (int i=1;i<=n;i++) { a[i] = ((LL)a[i] - (LL)b[i] * rate % MOD + MOD) % MOD; } elim(b, a, tar); return ; } int solve() { n--; int sgn = 1; for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { if(A[i][j] < 0) A[i][j] += MOD; } } for (int i=1;i<=n;i++) { for (int j=i+1;j<=n;j++) { if(A[j][i]) { elim(A[i], A[j], i); if(!A[i][i]) { swap(A[i], A[j]); sgn = -sgn; } } } } int sum = 1; for (int i=1;i<=n;i++) { sum = (LL)sum * A[i][i] % MOD; } return (sum * sgn + MOD) % MOD; } int main() { cin >> T; //多少组样例 while(T--) { cin >> r >> c; //r代表行数,c代表列数 G.n = r * c + 1; //图表里面的 n=行数*列数+1 /*初始化*/ G.clear(); for (int i=1;i<=G.n;i++) //每一个点的祖先都是自己 { pre[i]=i; } /*进行图的更新*/ for (int i=1;i<=r;i++) //输入r行,一行一个字符串 { scanf("%s", Map[i] + 1); //想要以这种方法输入,必须是char数组的形式,不能是string的形式 } for (int i=1;i<=r;i++) //遍历一共r行 { for (int j=1;j<=c;j++) //遍历一共j行 { if(Map[i][j] == 'D')//如果i不是最后一行,则D可以进行,否则就出去了 { int x=id(i,j); int y; if(i!=r) y=id(i+1,j); else y=G.n; G.AddEdge(x, y); int u = find(x); int v = find(y); if(u != v) pre[v] = u; //如果两者的祖先不相同,就进行合并 } if(Map[i][j] == 'U') { int x=id(i,j); int y; if(i!=1) y=id(i-1,j); else y=G.n; G.AddEdge(x, y); int u=find(x); int v=find(y); if(u!=v) pre[v]=u; } if(Map[i][j] == 'R') { G.AddEdge(id(i, j), j < c ? id(i, j + 1) : G.n); int u = find(id(i, j)), v = find(j < c ? id(i, j + 1) : G.n); if(u != v) pre[v] = u; } if(Map[i][j] == 'L') { G.AddEdge(id(i, j), j > 1 ? id(i, j - 1) : G.n); int u = find(id(i, j)), v = find(j > 1 ? id(i, j - 1) : G.n); if(u != v) pre[v] = u; } } } memset(vis, 0, sizeof(vis)); //初始化vis函数 bool ok = 1; for(int i=1;i<=G.n;i++) { if(vis[i]==0 && dfs(i)==0) { cout << "0" << endl; ok = 0; break; } } if(!ok) continue; memset(trid, 0, sizeof(trid)); n = 0; memset(tA, 0, sizeof(tA)); for (int i=1;i<=r;i++) { for (int j=1;j<=c;j++) { if(Map[i][j]=='.') { int u = find(id(i, j)); MatAddEdge(ID(u), ID(find(i < r ? id(i + 1, j) : G.n))); MatAddEdge(ID(u), ID(find(i > 1 ? id(i - 1, j) : G.n))); MatAddEdge(ID(u), ID(find(j < c ? id(i, j + 1) : G.n))); MatAddEdge(ID(u), ID(find(j > 1 ? id(i, j - 1) : G.n))); } } } int ci = 0, cj = 0; for (int i=1;i<=n;i++) { if(i != ID(find(G.n))) { ci++; cj = 0; for (int j=1;j<=n;j++) { if(j != ID(find(G.n))) { A[ci][++cj] = tA[i][j]; } } } } cout << solve() << endl; } return 0; }