GDUT 专题三 G - 食物链 (记忆化搜索)2022

本文解析了如何使用记忆化搜索算法解决Vjudge平台上的一个问题,涉及寻找从入度为0的节点到出度为0的节点的路径数量。通过模拟样例和理解题意,博主强调了处理单点特性和邻接表存储的重要性。代码实例展示了如何利用vector和dfs函数实现高效求解。

题面链接:https://vjudge.net/contest/478160#problem/G
input
10 16
1 2
1 4
1 10
2 3
2 5
4 3
4 5
4 8
6 5
7 6
7 9
8 5
9 8
10 6
10 7
10 9
output
9
数据范围
1≤N≤100000,0≤m≤200000
保证答案不会超过 int 的最大值

思路:我们首先应该在纸上模拟一边样例,这样可以更好地理解题意,也可以为我们写程序 提供思路。
在纸上模拟后,我们明白题目所求的是入度为0的点到出度为0的点的方案数。再看数据范围,直接暴搜肯定会超时,所以我们可以用记忆化搜索。
d[i]记录从点 i 出发到出度为0的总方案数,当搜索至 i 时,直接返回d[i]的值,实现记忆化。
另外有两处要注意的点
1)如何处理单个的点(即入度,出度均为0),依题意,单个点不能构成食物链,所以我们在更新ans时,应注意只更新入度为0,出度不为0的点。
2)使用vector存邻接表时,应先存入一个元素,这样在后面遍历邻接表时,才不会因为 i = 0,实际上要更新,而未更新。

(Ps, 这道题提醒了我们,一定要注意样例的实现,在生物中,其实一条食物链,一定要有生产者,但是可以不以最高级捕食者结尾;
还有就是考虑思考问题的方式,我最开始将问题翻译为求f[i][j](即入度为0的 i 点到出度为0的 j 点)的和,这就导致我们很难使用记忆化搜索,但是如果将问题翻译为求d[i],则记忆化搜索可以迎刃而解)

具体参考代码实现

AC代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 1e5;
int fir[N + 5], ind[N + 5], outd[N + 5], d[N + 5];
int n, m, ans;
vector <int> nex, ver;

inline LL read()
{
	char ch; bool flag = 0;
	while((ch = getchar()) < '0' || ch > '9')
		if(ch == '-')	flag = 1;
	LL res = ch - '0';
	while((ch = getchar()) >= '0' && ch <= '9')
		res = (res << 1) + (res << 3) + ch - '0';
	return flag ? -res : res;
}

void add(int x, int y)
{
	nex.push_back(fir[x]); fir[x] = nex.size() - 1; ver.push_back(y);
}

int dfs(int x)
{
	if(d[x])	return d[x];
	if(!outd[x])	return 1;
	for(int i = fir[x], v; v = ver[i], i; i = nex[i])
	{
		d[x] += dfs(v);
	}
	return d[x];
}

int main()
{
	n = read(); m = read();
	nex.push_back(0); ver.push_back(0);
	for(int i = 1; i <= m; ++i)
	{
		int x, y;
		x = read(); y = read();
		add(x, y);
		++ind[y]; ++outd[x];	
	}
	for(int i = 1; i <= n; ++i)
	{
		if(!ind[i] && outd[i])
			ans += dfs(i);
	}
	printf("%d\n", ans);
	return 0;
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值