Chocolate Milk(洛谷P2999)
拓扑排序
关于拓扑排序,这里不叙述太多,可参考本人CSDN。
值得注意的是,这不是一棵树吗?
FJ 发现对于牛奶来说有一种最多的方式从一个接口流到另一个接口。并且由于 FJ 是一个高效率的人,他需要确保每一个管道都有牛奶经过,也就是说,没有多余的管道。
所以,对于牛奶来说,最多只有一种方式从一个接口流到另一个接口。则不会有牛奶分开又聚到一起。
故有一个性质:除非节点的入度等于 ,否则任何出度大于 的节点的子节点都不能放置混合器。
表示如果在 结点造一个巧克力混合器,最多能经过的牛奶数(每个点初始为 )。
用拓扑排序遍历整棵树,顺便计算 。
- 只需要找到入度为 的结点,标记并放入队列。
for (int i = 1; i <= n; i++)
if (!ind[i]) q.push(i), ans[i] = check[i] = 1, cnt++;
- 每次找孩子只需要找出度为 的结点。
对于每个点如果它的出度大于 ,那么他所连的边就不可能成为巧克力混合器。
- 对于每个结点 ,若 值等于总边数,且入度不为 ,就输出。
AC CODE
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 99;
int n, m, t, tot, cnt;
int head[maxn], out[maxn], ind[maxn];
int ans[maxn];
bool check[maxn];
struct Edge
{
int to, next;
} e[maxn];
void add(int a, int b)
{
e[++tot].to = b;
e[tot].next = head[a];
head[a] = tot;
}
void topo()
{
queue<int> q;
for (int i = 1; i <= n; i++)
if (!ind[i])
q.push(i), ans[i] = check[i] = 1, cnt++;
while (!q.empty())
{
int tmp = q.front();
q.pop();
if (out[tmp] == 1)
{
int j = head[tmp];
ans[e[j].to] += ans[tmp];
if (--ind[e[j].to] == 0)
q.push(e[j].to);
}
}
}
signed main()
{
cin >> n;
for (int i = 1, a, b; i < n; i++)
{
cin >> a >> b;
add(a, b);
out[a]++;
ind[b]++;
}
topo();
for (int i = 1; i <= n; i++)
{
if (ans[i] == cnt && !check[i])
{
cout << i << endl;
}
}
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122194