E - 食物链

本文介绍了一种解决食物链问题的经典算法——带权并查集。该算法通过维护两个数组来记录节点间的关系及权重,利用并查集进行节点合并,并通过权重判断节点间的关系是否符合题目描述。

传送门:食物链
在这里插入图片描述
在这里插入图片描述
题意:题意简单,直接看题目即可。
思路:这是个经典的带权并查集题目了。
根据惯例,我们需要两个数组,一个是父亲节点数组p,另一个为记录x到p[x]的权值的d[x]数组,在这里规定x吃p[x]。
这道题的难点在于吃与被吃的数组d之间的关系
1.假如x与y是同类且用共同的祖宗节点,那么就判定d[x]-d[y])%3是否等于0,等于0就代表与所说的话一致,反之不一致,ans++;
2.假如x与y是同类且没用共同的祖宗节点,就让px的父亲节点为py,算出d[px],d[px]=d[y]-d[x];
3.假如x吃y且用共同的祖宗节点,那么就判定d[x]-d[y]-1)%3是否等于0,等于0就代表与所说的话一致,反之不一致,ans++;
4.假如x吃y且没用共同的祖宗节点,就让px的父亲节点为py,算出d[px],d[px]=d[y]-d[x]+1;
5.假如x,y大于n,ans++;
代码

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int N=5e4+5;
int p[N],d[N];
int find(int x)
{
	if(x!=p[x]) 
	{
		int t=find(p[x]);
		d[x]+=d[p[x]];
		p[x]=t;
	}
	return p[x];
}
int main()
{
	int n,k;
	scanf("%d%d",&n,&k);
	for (int i = 1; i <= n; i ++ ) p[i] = i;
	int ans=0;
	while(k--)
	{
		int t,x,y;
		scanf("%d%d%d",&t,&x,&y);
		int px=find(x),py=find(y);
		if (x > n || y > n) ans ++ ;
		else
		{
			if(t==1)
			{
				if(px==py&&(d[x]-d[y])%3) ans++;
				else if(px!=py) 
				{
					p[px]=py;
					d[px]=d[y]-d[x];
				}	
			}
			else{
				if(px==py&&(d[x]-d[y]-1)%3) ans++;
				else if(px!=py)
				{
					p[px]=py;
					d[px]=d[y]-d[x]+1;
				}
			}
			
		}
		
	} 
	printf("%d",ans);
	return 0;
}
### P4017 最大食物链计数问题的解决方案 对于最大食物链计数问题,可以采用图论中的拓扑排序以及动态规划相结合的方法来求解。该方法能够有效地处理有向无环图(DAG),并计算最长路径。 #### 方法概述 通过构建邻接表表示的食物网关系图,并利用入度数组记录每个节点的前驱数量。随后执行Kahn算法进行拓扑排序,在此过程中维护一个dp[]数组用于存储到达当前顶点的最大长度。最终遍历所有可能终点得到全局最优解。 #### 算法描述 - 初始化阶段:读取输入数据建立边集E和相应的邻接表G;初始化入度indegree[]为零。 - 构建过程:根据题目给定条件更新每条边对应的起点与终点之间的连接情况,同时增加相应结点的入度值。 - Kahn算法实施:创建队列Q保存所有入度为0的源点作为起始位置;当队列不为空时循环取出首元素u,尝试访问其相邻的所有v节点,如果发现某个被指向的位置满足入度减至0,则将其加入到待处理集合中继续扩展搜索空间。 - 动态转移方程定义:设f[i]代表以第i个物种结尾所能形成的食物链条数目总和,那么状态转换表达式可写作`f[v]=max{f[u]+1}`其中(u,v)属于已知存在的捕食者—猎物关联对。 - 结果汇总:统计整个生态系统内任意生物种群所参与构成的有效营养级联规模峰值即为目标函数输出结果。 下面是具体的Java代码实现: ```java import java.util.*; public class Main { static final int MAXN = 100005; static List<Integer>[] adjList = new ArrayList[MAXN]; static int[] indegree = new int[MAXN], dp = new int[MAXN]; public static void main(String[] args) { Scanner sc = new Scanner(System.in); // Read input data and initialize graph structure int n = sc.nextInt(), m = sc.nextInt(); for (int i = 0; i < n + 1; ++i) adjList[i] = new ArrayList<>(); while (--m >= 0){ int u = sc.nextInt(), v = sc.nextInt(); adjList[u].add(v); indegree[v]++; } Queue<Integer> q = new LinkedList<>(); for(int i=1;i<=n;++i) if(indegree[i]==0)q.offer(i); int ans = 0; while (!q.isEmpty()) { Integer curNode = q.poll(); for(Integer next : adjList[curNode]){ dp[next] = Math.max(dp[next], dp[curNode] + 1); --indegree[next]; if (indegree[next] == 0) q.add(next); ans = Math.max(ans, dp[next]); } } System.out.println(ans+1); // Add one because we count edges instead of nodes. } } ``` 上述程序实现了基于DAG上的最优化策略,适用于解决此类具有层次结构特征的问题实例[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值