题目传送门:【BZOJ 4562】
题目大意:现在给你 n 个物种和 m 条能量流动关系(1 ≤ N ≤ 100000,0 ≤ m ≤ 200000),求其中的食物链条数。物种的名称从 1 到 n 编号,M条能量流动关系形如(a1 b1),(a2 b2),(a3 b3)……(am-1 bm-1),(am bm)
其中(ai bi)表示能量从物种 ai流向物种 bi。注意单独的一种孤立生物不算一条食物链。数据保证符合生物学特点,且不会有重复的能量流动关系出现。
题目分析:
由题,根据题目性质,我们可以发现,整个图就是一个 DAG。所以,我们就根据这个性质,从所有的起始点开始走,然后递推求出每个点对应的食物链条数;最后统计所有终止点的总数,全部加起来即为答案。
起始点:指入度为 0,出度不为 0 的点。
终止点:指出度为 0,入度不为 0 的点。
因为入度/出度都为 0 的点不能被统计,所以我们要在开始时单独判断一次。
下面附上代码:
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #include<queue>
- using namespace std;
- const int MX=100005;
- struct Edge{
- int to,next;
- }edge[MX*4];
- int n,m,head[MX],now=0,ind[MX],outd[MX];
- int dp[MX],ans=0;
- queue<int> q,st,ed;
- inline void adde(int u,int v){
- edge[++now].to=v;
- edge[now].next=head[u];
- head[u]=now;
- }
- void bfs(int s){ //名为 bfs,实际上是拓扑排序
- dp[s]=1;
- q.push(s);
- while (!q.empty()){
- int u=q.front();
- q.pop();
- for (int i=head[u];i;i=edge[i].next){
- int v=edge[i].to;
- dp[v]+=dp[u];
- ind[v]–;
- if (ind[v]==0) q.push(v);
- }
- }
- }
- int main(){
- int a,b;
- scanf(”%d%d”,&n,&m);
- for (int i=1;i<=m;i++){
- scanf(”%d%d”,&a,&b);
- adde(a,b);
- ind[b]++,outd[a]++;
- }
- for (int i=1;i<=n;i++){ //判断哪些点是起始点,哪些点是终止点,哪些点不能被统计
- if (ind[i]==0 && outd[i]==0) continue;
- if (ind[i]==0){
- st.push(i);
- }
- if (outd[i]==0){
- ed.push(i);
- }
- }
- while (!st.empty()){
- int i=st.front();
- bfs(i);
- st.pop();
- }
- while (!ed.empty()){
- int i=ed.front();
- ans+=dp[i];
- ed.pop();
- }
- printf(”%d”,ans);
- return 0;
- }