[Edp] lcLCP 07. 传递信息(暴搜+dp求方案+矩阵乘法+好题)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Edp] lcLCP 07. 传递信息(暴搜+dp求方案+矩阵乘法+好题)相关的知识,希望对你有一定的参考价值。
1. 题目来源
链接:LCP 07. 传递信息
2. 题目解析
数据量很小,也是常见的题型了,直接暴搜做就行了。
就询问能否从点 0,恰好经过 k
步到达点 n-1
。那么可以直接暴力 dfs
,k
数据范围很小,最大就是 5。dfs
代码非常容易理解,递归深度就是经过的层数,不会爆栈。
本题如果说是求一种合法方案,并且将答案搞得很大的时候,显然就是迭代加深了。
在离散数学中图论部分有讲:邻接矩阵相乘 k
次后,A[i][j]=x
代表从 i
点到达 j
恰好经过 k
步的方案数。如果要求从 i
到 k
小于等于 k
步的方案数时,需要将前面的矩阵该位置数全部相加起来。
其实也就是可达矩阵。
关于证明请看这篇博文:矩阵乘法与邻接矩阵,也可在网上自行搜索证明过程。
本题就是一个裸的邻接矩阵相乘 k
次的问题了。
本题 dp
也是可以处理的。
- 状态定义:
f[i][j]
经过i
步到从 0 点出发达点j
的方案数。 - 初始化:
f[0][0]=1
起点自身为 0 步。 - 状态转移:
f[i][j]=f[i-1][k1]+f[i-1][k2]+f[i-1][k3]...
这些k1、k2、k3
的下个点都是j
。 - 答案:
f[k][n-1]
。
这个状态转移十分自然,看程序即可。
本题 bfs
也可行,按层拓展,拓展 5 层即可。
时间复杂度:
O
(
n
k
)
O(n^k)
O(nk)
空间复杂度:
O
(
n
+
k
)
O(n+k)
O(n+k)
dfs暴搜
class Solution {
public:
void dfs(int n, vector<vector<int>>& relation, int &k, int cur, int cnt, int& res) {
if (cnt > k) return ;
if (cur == n - 1 && cnt == k) {
res ++ ;
return ;
}
for (auto& e : relation) {
if (e[0] == cur) {
dfs(n, relation, k, e[1], cnt + 1, res);
}
}
}
int numWays(int n, vector<vector<int>>& relation, int k) {
int res = 0;
dfs(n, relation, k, 0, 0, res);
return res;
}
};
邻接矩阵乘法,代码摘自:离散数学,计算可达矩阵
typedef long long ll;
const ll mod = 1e9+7;
struct node {
ll mat[15][15];//定义矩阵
}x,y;
int len;
node mul(node x,node y){//矩阵乘法
node tmp;
for(int i=0;i<len;i++){
for(int j=0;j<len;j++){
tmp.mat [i][j]=0;
for(int k=0;k<len;k++){
tmp.mat [i][j]+=(x.mat [i][k]*y.mat [k][j])%mod;
}
tmp.mat [i][j]=tmp.mat[i][j]%mod;
}
}
return tmp;
}
node matpow(node x,node y,int num){//矩阵快速幂
while(num){
if(num&1){
y=mul(y,x);
}
x=mul(x,x);
num=num>>1;
}
return y;
}
class Solution {
public:
int numWays(int n, vector<vector<int>>& relation, int k) {
node x,res;
len = n;
memset(x.mat,0,sizeof(x.mat));
for(auto& e:relation){
x.mat[e[0]][e[1]] = 1;
}
res = matpow(x,x,k-1);
return res.mat[0][n-1];
}
};
dp:
class Solution {
public:
int numWays(int n, vector<vector<int>>& relation, int k) {
vector<vector<int>> f(k + 1, vector<int>(n));
f[0][0] = 1;
for (int i = 1; i <= k; i ++ ) {
for (auto e : relation) {
int x = e[0], y = e[1];
f[i][y] += f[i - 1][x];
}
}
return f[k][n - 1];
}
};
bfs
按层拓展即可:
class Solution {
public:
int numWays(int n, vector<vector<int>>& relation, int k) {
int res = 0;
queue<int> q;
q.push(0);
int depth = 0;
while (q.size()) {
if (depth == k) {
while (q.size()) {
auto t = q.front(); q.pop();
if (t == n - 1) res ++ ;
}
break;
}
int len = q.size();
while (len -- ) {
auto t = q.front(); q.pop();
for (auto e : relation) {
int x = e[0], y = e[1];
if (x == t) {
q.push(y);
}
}
}
depth ++ ;
}
return res;
}
};
以上是关于[Edp] lcLCP 07. 传递信息(暴搜+dp求方案+矩阵乘法+好题)的主要内容,如果未能解决你的问题,请参考以下文章
[M贪心] lcLCP30. 魔塔游戏(STL优先队列+堆+贪心)