[Edp] lcLCP 07. 传递信息(暴搜+dp求方案+矩阵乘法+好题)

Posted Ypuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Edp] lcLCP 07. 传递信息(暴搜+dp求方案+矩阵乘法+好题)相关的知识,希望对你有一定的参考价值。

1. 题目来源

链接:LCP 07. 传递信息

2. 题目解析

数据量很小,也是常见的题型了,直接暴搜做就行了。

就询问能否从点 0,恰好经过 k 步到达点 n-1。那么可以直接暴力 dfsk 数据范围很小,最大就是 5。dfs 代码非常容易理解,递归深度就是经过的层数,不会爆栈。

本题如果说是求一种合法方案,并且将答案搞得很大的时候,显然就是迭代加深了。


在离散数学中图论部分有讲:邻接矩阵相乘 k 次后,A[i][j]=x 代表从 i 点到达 j 恰好经过 k 步的方案数。如果要求从 ik 小于等于 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求方案+矩阵乘法+好题)的主要内容,如果未能解决你的问题,请参考以下文章

EDP加入VertiGIS,打开北欧市场

[E双指针] lcLCP28. 采购方案(双指针+二分)

[M贪心] lcLCP30. 魔塔游戏(STL优先队列+堆+贪心)

[M贪心] lcLCP30. 魔塔游戏(STL优先队列+堆+贪心)

vbyone和EDP区别

edp与edt哪个好?都有哪些区别?