题解 P2999【[USACO10NOV]Chocolate Milk S】

题目

这题应该使用拓扑排序。

思路

给定每个挤奶器牛奶流量 \(1\), 并用数组 $milk $ 记录每个节点可以流经来自多少个不同挤奶器的牛奶,子接口可以流经来自父接口的所有牛奶。
进行拓扑排序,若某节点的流量为挤奶器的数量,则该节点可以放置巧克力混合器。

对于牛奶来说,最多只有一种方式从一个接口流到另一个接口。

因此不会有牛奶分流后再重新聚集到一点,即除了入度为 \(0\) 的节点外,一个出度大于 \(1\) 的节点的子节点都不能放置巧克力混合器。
其余的细节参考代码及注释。


#include<bits/stdc++.h>

using namespace std;

const int N=100005;
vector<int>G[N];
queue<int>q;
int ind[N],f[N],milk[N];
bool ism[N];
int n,m,sum;
void topo()
{
    for(int i=1;i<=n;i++)
    {
        if(!ind[i])
        {
            q.push(i);
            ism[i] = true;   //标记挤奶器 
            milk[i] = 1;     //记录每个接口可以流经来自多少个挤奶器的牛奶
            sum++;           //一共有多少个挤奶器
        }
    }
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        if(G[u].size()>1)    //牛奶不会在分流后聚集到一点 
        {
            continue;
        }
        for(int i=0;i<G[u].size();i++)
        {
            int v = G[u][i];
            ind[v]--;
            milk[v]+=milk[u];   //上一个接口的牛奶可以流向该接口 
            if(!ind[v]) q.push(v);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)  //一共有n-1条管道
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        ind[v]++;    //记录出度 
    }
    topo();
    for(int i=1;i<=n;i++)
    {
        if(!ism[i]&&milk[i]==sum)   //如果不是挤奶器,并且来自所有挤奶器的牛奶都可以流经该接口 
        {
            printf("%d\n",i);
        }
    }
    return 0;
}
posted @ 2021-05-01 16:05  我和鱼过不去  阅读(67)  评论(0)    收藏  举报