DFS的记忆化

这篇博客探讨了如何在最大食物链计数问题中利用记忆化DFS和动态规划提高算法效率。文章通过示例代码详细解释了未记忆化的DFS算法,然后引入了一个记忆化数组,用于存储中间状态,从而避免重复计算。作者展示了如何从终点开始,使用记忆化的DP数组进行优化,并解释了数组在回溯过程中的作用。最后,给出了优化后的代码实现,实现了从起点到终点的最短路径计数。
摘要由CSDN通过智能技术生成

点击了解:DFS–记忆化DFS–DP之间的联系

例题:最大食物链计数(涉及图论)

下面的代码是没有记忆化的代码

#include<bits/stdc++.h> 
using namespace std;
#define mod 80112002
vector<int> G[5050];
int rud[5050];
queue<int> q;
long ans = 0;
int dfs(int x)
{	
	if(!G[x].size())
	{
		ans++;
		return 0;
	}
	for(int y=0; y<G[x].size(); y++)
	{
		dfs(G[x][y]);
	}

} 
int main()
{
	int n, m; 
	cin >> n >> m;
	for(int i=1; i<=m; i++)
	{
		int a, b;
		cin >> a >> b;
		G[a].push_back(b);
		rud[b]++; 
	}
	 
	for(int i=1; i<=n; i++)
		if(rud[i] == 0)
		{
			q.push(i);
		}
	while(!q.empty())
	{
		int now = q.front();
		q.pop();
		dfs(now);
	}
	printf("%ld", ans%mod);
	return 0;
}

用一个数组去记住中间值,有值就直接用不用在dfs------记忆化
就是相反的,从终点开始的 dp数组内 存的是什么?

#include<bits/stdc++.h> 
using namespace std;
#define mod 80112002
vector<int> G[5050];
int rud[5050];
queue<int> q;
long ans = 0;
int dp[5050];//dp应该是把中间值记下来了 至于这个数组存的是什么 就看代码顶部的链接 
int dfs(int x)//输入度为 0 的结点   记忆化dfs dfs是下往上 
{	
	int res = 0;
	if(!G[x].size())//到达终点
	{
		return dp[x] = 1;//到达底部 开始向上回溯 
	}
	for(int y=0; y<G[x].size(); y++)
	{
		int next = G[x][y];
		res += dp[next]>0 ? dp[next]:dfs(next); //要么是 += 要么是 后面带大括号  
		//如果存在dp这个数字,说明这个中间值已经存过了,则直接用 //三目运算符:如果dp[nxt]存在则等于自己,否则等于dfs
		res = res % mod; //回溯时就会从上面的语句开始 
	}
	//这就是上一个 dfs的入口,从这里又到达了 res = res % mod 的地方,把res向上传递,直到到达顶点 得到的新的 res,最终dfs的返回值为res
	return dp[x] = res;	//所以说最终 res 为以这次起点到达终点的 路径的条数 
} 
int main()
{
	int n, m; 
	cin >> n >> m;
	for(int i=1; i<=m; i++)
	{
		int a, b;
		cin >> a >> b;
		G[a].push_back(b);
		rud[b]++; 
	}
	 
	for(int i=1; i<=n; i++) //把入度为 0 的结点也就是起点入队 
		if(rud[i] == 0)
		{
			q.push(i);
		}

	while(!q.empty()) //以队列里的每个结点分别为起点进行 dfs求 ans路径的条数 
	{
		int now = q.front();
		q.pop();
		ans = (ans + dfs(now)) % mod; //也就是说一个数如果被取余 那么部分取余后相加也没问题 
	}
	printf("%ld", ans);
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值