点击了解: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;
}