1. 程式人生 > 實用技巧 >暑假集訓Day13 食物鏈

暑假集訓Day13 食物鏈

題目大意

現在給你n個物種和m條能量流動關係,求其中的食物鏈條數。

物種的名稱為從1到n的編號。

m條能量流動關係形如
\(a_1 b_1\)
\(a_2 b_2\)
\(a_3 b_3\)
\(a_4 b_4\)
...
\(a_m b_m\)
其中\(a_i b_i\)表示能量從物種\(a_i\)流向物種\(b_i\) 。注意單獨的一種孤立生物不算一條食物鏈。

輸入格式

第一行兩個整數n和m,接下來m行每行兩個整數\(a_i b_i\)描述m條能量流動關係。

(保證輸入資料符合生物學特點,即不存在環,且不會有重複的能量流動關係出現)

輸出格式

一個整數,即食物網中的食物鏈條數。

樣例

樣例輸入

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

樣例輸出

9

演算法分析:

  • 這是一個很裸的圖論的題了(考試爆零真的是我的原因了)
  • 其實真的很裸沒啥可分析的………………
  • 跑拓撲或者dfs都行
  • 直接看程式碼吧

程式碼展示

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int cnt,n,m;
int head[maxn],rd[maxn],cd[maxn],dp[maxn];

struct edge{int to,next;}a[maxn];

void add(int x,int y){
	a[++cnt].to = y;
	a[cnt].next = head[x];
	head[x] = cnt;
}

queue<int> q;

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= m;++i){
		int x,y;scanf("%d%d",&x,&y);
		rd[y]++;//入度
		cd[x]++;//出度
		add(x,y);
	}
	for(int i = 1;i <= n;++i){
		if(!rd[i]){//沒有入度說明是根節點
			q.push(i);
			if(cd[i] != 0)dp[i] = 1;//如果不是葉子節點 就將鏈數置為1
		}
	}
	while(!q.empty()){
		int x = q.front();//取出隊首
		q.pop();
		for(int i = head[x];i;i = a[i].next){//依次遍歷隊首每一個兒子
			dp[a[i].to] += dp[x];//兒子的鏈數 += 父親的鏈數(自己想為啥吧 要不然就畫圖)
			rd[a[i].to] -= 1;//減去當前父親的入度 已經計算過了 方便再以這個兒子跑拓撲
			if(rd[a[i].to] == 0){//類似於深搜 將沒有入度的點入隊
				q.push(a[i].to);
			}
		}
	}
	int ans = 0;
	for(int i = 1;i <= n;++i)if(cd[i] == 0)ans += dp[i];//把各個葉子節點的權值加上
	printf("%d",ans);
	return 0;
}

考試的時候沒看懂樣例 鏈數沒數過來 呀咦惹

謝謝觀看
點個關注 >,<