白金元首与独舞 有向图的生成树计数
题目
(白金元首与独舞)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;
}
原文地址:https://www.cnblogs.com/liweihang/p/13680076.html
- AutoFlowLayout-多功能流式布局与网格布局控件
- RBAC新解:基于资源的权限管理(Resource-Based Access Control)
- 基于开源项目搭建属于自己的技术堆栈
- Redis整合Spring项目搭建实例
- SpringMVC+Hibernate +MySql+ EasyUI实现POI导出Excel(二)
- Nginx+Tomcat+Redis负载均衡Session共享实现超级简单(CentOS6.9系统 Java版本)
- Apache Ignite——新一代数据库缓存系统
- 微信JSSDK接入Java版--步骤及问题处理和解决
- 微信企业号回调模式配置讲解 Java Servlet+Struts2版本 echostr校验失败解决
- Android Material Design系列之RecyclerView和CardView
- 在Linux安装ASP.Net Core的运行时(Runtime)
- 使用xUnit为.net core程序进行单元测试(下1)
- Otto开发初探——微服务依赖管理新利器
- Apache Eagle——eBay开源分布式实时Hadoop数据安全方案
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- elasticSearch学习(五)
- MySQL进阶:索引与优化
- CentOS7搭建Zabbix4.2系统
- vue项目更换favicon.ico
- 一种O(n)的排序——计数排序引发的围观风波
- LeetCode 04寻找两个正序数组的中位数(困难)二分法
- Java程序员面试必备:Volatile全方位解析
- HTTP协议基础及发展历史
- Vi 和 Vim 的使用
- k8s删除Terminating状态的命名空间
- CentOS7下vsftpd over SSL/TLS加密传输配置实践
- Xargs Sh -c Skipping the First Argument
- Centos系统安装
- Python 为什么能支持任意的真值判断?
- Python 为什么要在 18 年前引入布尔类型?且与 C、C++ 和 Java 都不同?