白金元首与独舞 有向图的生成树计数
题目
(白金元首与独舞)https://ac.nowcoder.com/acm/problem/14758
题目描述
元首把花园分为 n 行 m 列的网格。每个格子中都可以放置一个标识,指向上、下、左、右四个方向中的任意一个。元首位于一个格子时,会按照其中标识所指的方向进入周围的格子,或者走出花园(即目的格子不在网格之内)。举个例子 —— 对于下面的放置方式,元首从第 3 行第 2 列的格子开始,会沿着以红色标出的路径走出花园;从第 2 行第 2 列的格子开始,则会在以蓝色标出的环路内不断地行走。
元首已经设计好了大部分格子的标识。元首用字符 L、R、U、D 分别表示指向左、右、上、下四个方向的标识,用字符 . 表示未决定的格子。现在,元首希望将每个 . 替换为 L、R、U、D 中任意一种,使得从花园中的任意一个格子出发,按照上述规则行走,都可以最终走出花园。
你需要编写程序帮助元首计算替换的不同方案数。两个方案不同当且仅当存在一个格子,使得两个方案中该格子内的标识不同。当然,由于答案可能很大,只需给出方案数除以 109+7 所得的余数即可。
输入描述:
输入的第一行包含一个正整数 T —— 测试数据的组数。接下来包含 T 组测试数据,格式如下,测试数据间没有空行。
第 1 行:两个空格分隔的正整数 n、m —— 依次表示花园被分成的行数和列数。
接下来 n 行:每行一个长度为 m 的由字符 L、R、U、D 和 . 组成的字符串 —— 表示花园内已经确定的格子状态。
输出描述:
对于每组测试数据输出一行 —— 满足条件的方案数除以 109 + 7 所得的余数。
输入
5
3 9
LLRRUDUUU
LLR.UDUUU
LLRRUDUUU
4 4
LLRR
L.LL
RR.R
LLRR
4 3
LRD
LUL
DLU
RDL
1 2
LR
2 2
..
..
输出
3
8
0
1
192
说明和备注
说明
第 1 组数据中,将惟一的 . 替换成 R、U 或 D 均满足要求。
第 2 组数据中,将左上方和右下方的两个 . 分别替换成 LR、LU、LD、UR、UU、UD、DR 或 DD 均满足要求。
第 3 组数据中,没有待决定的格子,原本的安排会使得元首陷入无尽的环路,故答案为 0。该组数据与【题目描述】中的例子相同。
第 4 组数据中,也没有待决定的格子,但原本的安排已经满足要求,故答案为 1。
备注:
对于所有数据,有 1≤T≤10,1≤n,m≤200,0≤k≤min(nm,300)。
思路
所有的点都可以到达边界外,如果有环就不可以。
if如果有环:0
else if如果没有'.':1
else{
如果我们把边界外当作一个点1,那么就是一个合格的方案就是
每个点形成了一个1为根的有向生成树。
如果我们直接生成树计数。那么n^3会T。
我们注意到'.'的个数最多300.那么我们考虑'.'为节点。因为除了'.'每个点
的路径一定是确定。而且只能到一个地方。就是树上已经确定的边。所以如果一个'.'可以到达另外一个'.'
那么我们向他们连边。然后有向生成树计数就可以了。
}
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int mod = 1e9+7;
LL a[310][310];
void gcd(LL a,LL b,LL& x,LL& y) {
if(!b) {
x=1;
y=0;
} else {
gcd(b,a%b,y,x);
y-=x*(a/b);
}
}
LL inv(LL a) {
LL x,y;
gcd(a,mod,x,y);
return (x%mod+mod)%mod;
}
LL gauss(int n) {
bool f=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
a[i][j]=(a[i][j]+mod)%mod;
for(int i=2; i<=n; i++) {
int r=i;
for(int j=i+1; j<=n; j++)
if(a[j][i]>a[r][i])
r=j;
if(r!=i) {
for(int j=i; j<=n+1; j++)
swap(a[i][j],a[r][j]);
f^=1;
}
LL w=inv(a[i][i]);//
for(int j=i+1; j<=n; j++) {
for(int k=n+1; k>=i; k--) {
a[j][k]=(a[j][k]-1ll*a[j][i]*w%mod*a[i][k]%mod+mod)%mod;//
}
}
}
LL ans=f?mod-1:1;
for(int i=2; i<=n; i++)
ans=1ll*ans*a[i][i]%mod;
return ans;//
}
char s[310][310];
int vis[310][310];
int xx[]= {0, 1, 0, -1};
int yy[]= {1, 0, -1, 0};
int n, m;
int dfs(int i, int j, int tot) {
vis[i][j]=tot;
int k=0;
if(s[i][j]=='R')
k=0;
if(s[i][j]=='D')
k=1;
if(s[i][j]=='L')
k=2;
if(s[i][j]=='U')
k=3;
int x=i+xx[k], y=j+yy[k];
if(s[x][y]!='.'&&x>=1&&x<=n&&y>=1&&y<=m) {
if(vis[x][y]!=0&&vis[x][y]!=tot) {
return 1;
}
else if(vis[x][y]==tot){
return 0;
}
else{
return dfs(x, y, tot);
}
}
return 1;
}
int id[205][205];
int dp[205][205];
int DP(int i, int j) {//记忆化DP每个坐标能够到达的点
if(dp[i][j]) {
return dp[i][j];
}
if(s[i][j]=='.')
return dp[i][j]=id[i][j];
if(!(i>=1&&i<=n&&j>=1&&j<=m)) {
return dp[i][j]=1;
}
int k=0;
if(s[i][j]=='R')
k=0;
if(s[i][j]=='D')
k=1;
if(s[i][j]=='L')
k=2;
if(s[i][j]=='U')
k=3;
int x=i+xx[k], y=j+yy[k];
if(x>=1&&x<=n&&y>=1&&y<=m) {
return dp[x][y]=DP(x, y);
} else {
return dp[x][y]=1;
}
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) {
scanf("%s", s[i]+1);
}
memset(vis, 0, sizeof(vis));
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
memset(id, 0, sizeof(id));
int f=0, siz=1, tot=1;
for(int i=1; i<=n&&!f; i++) {
for(int j=1; j<=m&&!f; j++) {
if(s[i][j]!='.'&&dfs(i, j, ++tot)==0) {
f=1;
}
if(s[i][j]=='.') {//对每个'.'编号
++siz;
id[i][j]=siz;
}
}
}
if(f) {
printf("%d\n", 0);
continue;
} else if(siz==0) {
printf("1\n");
continue;
} else {
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
if(s[i][j]=='.') {
int u=id[i][j];
for(int k=0; k<4; k++) {
int x=i+xx[k], y=j+yy[k];
int v=DP(x, y);
a[u][v]--, a[u][u]++;
}
}
}
}
printf("%lld\n", gauss(siz));
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)