动态规划——最大食物链计数

动态规划——最大食物链计数

来自洛谷P4017 最大食物链计数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ISfLbDZQ-1648372793589)(C:\Users\86180\AppData\Roaming\Typora\typora-user-images\image-20220327165549777.png)]

解题思路


首先这道题先学会合理使用vector,因为这里食物链的表示其实类似于有向图的邻接表,而一般来说我们需要使用队列的结构,但是通过vector,可以很容易得就模拟出队列的状态,并且可以通过下标来访问!

在这里我们只需要记录下所有的非被捕食者,然后采取DFS记忆化搜索的方式即可

要注意mod

另外还需要注意下标,因为读入的下标的是从1开始的!!

代码实现

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,n) for(int i=s;i<n;i++)
const int SIZE = 5001;
const int mod = 80112002;
vector<int> Eat[SIZE];
bool HEat[SIZE];
int res[SIZE];

int dfs(int i)
{
	int ans = 0;
	if (Eat[i].size() < 1)
		return res[i] = 1;
	if (res[i] != 0)
		return res[i];
	rep(j, 0, Eat[i].size())
	{
		int &temp = Eat[i][j];
		ans+= res[temp] ? res[temp] : dfs(temp);
		ans %=mod;

	}

	return res[i] = ans;


}



int main()
{
	int n,m;
	scanf("%d %d", &n, &m);
	memset(res, 0, sizeof(res));
	memset(HEat, 0, sizeof(HEat));
	rep(i, 0, m)
	{
		int x, y;
		scanf("%d %d", &x, &y);
		Eat[y].push_back(x);
		HEat[x] = true;//x是被捕食者
	}
	int ans = 0;
	rep(i, 1, n+1)
	{
		if (!HEat[i])
			ans = (ans + dfs(i)) % mod;
	}
	printf("%d", ans);

	return 0;

}

附加部分

另外这道题还可以采取拓扑排序的方式

记录下所有入度为0的点,然后依次向后查找,直到找到出度为0的点

#include<bits/stdc++.h>
using namespace std;
int n, m, ru[5005], chu[5005], a, b, f[5005], ans;
int mp[5005][5005];
queue<int> q;
const int mod =80112002;
int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		cin >> a >> b;
		mp[b][a] = 1;//记录关系
		ru[a]++;
	    chu[b]++;//记录入度和出度
	}
	for (int i = 1; i <= n; i++)
	{
		if (ru[i] == 0)
		{
			f[i] = 1;
			q.push(i);
		}
	}
	while (!q.empty())
	{
		int a = q.front();
		q.pop();
		for (int i = 1; i <= n; i++)
		{
			if (mp[a][i] == 0)
				continue;
			f[i] += f[a];
			f[i] %= mod;
			ru[i]--;
			if (ru[i] == 0)
			{
				if (chu[i] == 0)
				{
					ans += f[i];
					ans %= mod;
					continue;


				}
				q.push(i);
			}

		}


	}
	cout << ans;
	return 0;



}

注意

比较关键的点在于对f[i]的初始化! 以及入度要减1!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值