最大食物链计数(记忆化搜索/拓扑排序)

最大食物链计数(记忆化搜索/拓扑排序)_第1张图片

传送门

根据题意我们不难理解该题的意思就是求出一个图中的食物链一共有多少条,而我们知道食物链的起点是生产者不会捕食其他生物,终点时不会被捕食的捕食者,仔细想我们会发现,生产者的入度为0,而不会被捕食的捕食者的出度为0,从入度为0的点开始,这不是拓扑排序的特点吗,因此考虑使用拓扑排序

最大食物链计数(记忆化搜索/拓扑排序)_第2张图片

 如上图所示,以蓝色点为起点,红色点为终点,我们不难发现,到达红色点路径数取决于到达与之相连的2、3、4点,而到达它们的路径数又取决于与之相连的点,以此类推

我们假设起点的路径数为1,那么在拓扑排序的过程中,我们只需将与当前相连的点的路径数+=当前点的路径数即可

第一轮:删除 1 号蓝色点,1 号蓝色点可以到的点(2 号点、3 号点)都加 1

最大食物链计数(记忆化搜索/拓扑排序)_第3张图片

第二轮:删除 2 号点,2 号点可以到的点(3 号点、5 号红色点)都加 1。此时 3 号点答案为2,5 号点答案为 1

最大食物链计数(记忆化搜索/拓扑排序)_第4张图片

第三轮:删除 3 号点,3号点可以到的点(4 号点、5 号红色点)都加 2。此时 5 号点答案为 3,4 号点答案为 2

最大食物链计数(记忆化搜索/拓扑排序)_第5张图片

第四轮:最后删除 4 号点,4 号点可以到的点(5 号红色点)加 2,此时 5 号点答案为 5

最大食物链计数(记忆化搜索/拓扑排序)_第6张图片

可见全图只有 5 号一个红色点,那么答案就是 5 号点的答案———— 5 了

最大食物链计数(记忆化搜索/拓扑排序)_第7张图片

那么代码实现就很简单了!(题解参考自)

#include
#include
#include

using namespace std;

const int MAX=5e4,mod=80112002;

vectormapp[MAX];
int arr1[MAX];//记录各个顶点的入度 
int arr2[MAX];//出度 
int ans[MAX];//以ans[i]为终点的食物链数
int n,m;

void fun(){
	stackstk;
	for(int i=1;i<=n;i++){
		if(arr1[i]==0){
			stk.push(i);//将入度为0的点入栈 
			ans[i]=1;
		}
	}
	while(!stk.empty()){
		int cur=stk.top();
		stk.pop();
		int sizee=mapp[cur].size();
		for(int i=0;i>n>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		mapp[x].push_back(y);
		arr1[y]++;//入度
		arr2[x]++; //出度
	}
	fun();
	for(int i=1;i<=n;i++){
		if(arr2[i]==0){
			res=(res+ans[i])%mod;//注意可能有多个出度为0的点 
		}
	}
	cout<

当然像这种求解从起点开始到终点有多少条路径的题目也可以使用DFS来做

只需循环遍历起点进行DFS,只要到达一次终点就ans++即可

#include
#include

using namespace std;

const int MAX=5e4;

vectormapp[MAX];
int arr1[MAX];//记录各个顶点的入度 
int arr2[MAX];//出度 
int n,m,ans;

void dfs(int cur){
	if(arr2[cur]==0){//终点为出度为0的点 
		ans++;
		return ;
	}
	int sizee=mapp[cur].size();
	for(int i=0;i>n>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		mapp[x].push_back(y);
		arr1[y]++;
		arr2[x]++; 
	}
	for(int i=1;i<=n;i++){
		if(arr1[i]==0){//从入度为0的顶点开始遍历 
			dfs(i);
		}
	}
	cout<

 但是该题边的数量很多,因此会超时

我们考虑用记忆化搜索进行优化

#include
#include
#include

using namespace std;

const int MAX=5e4,mod=80112002;

vectormapp[MAX];
int arr1[MAX];//记录各个顶点的入度 
int arr2[MAX];//出度 
int book[MAX];//记忆数组,记录从i到终点有多少条路径 
int n,m;

int dfs(int cur){
	if(arr2[cur]==0)return 1;//出度为0的点 
	if(book[cur])return book[cur];//记忆
	int sizee=mapp[cur].size();//临接边数
	int sum=0;
	for(int i=0;i>n>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		mapp[x].push_back(y);
		arr1[y]++;//入度
		arr2[x]++; //出度
	}
	for(int i=1;i<=n;i++){
		if(arr1[i]==0){
			res=(res+dfs(i))%mod;//注意可能有多个入度为0的点 
		}
	}
	cout<

你可能感兴趣的:((算法+例题)讲解,算法,图论)