动态规划——最大食物链计数
来自洛谷P4017 最大食物链计数
解题思路
首先这道题先学会合理使用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!!!