当前位置 博文首页 > 文章内容

    [Luogu] P2812 校园网络【[USACO]Network of Schools加强版】

    作者: 栏目:未分类 时间:2020-11-03 9:01:57

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    \(Link\)

    Description

    共有\(n\)所学校 \((1 \leq n \leq 10000)\),已知他们实现设计好的网络共\(m\)条线路,为了保证高速,网络是单向的。现在请你告诉他们至少选几所学校作为共享软件的母机,能使每所学校都可以用上。再告诉他们至少要添加几条线路能使任意一所学校作为母机都可以使别的学校使用上软件。

    Solution

    先跑一遍\(Tarjan\)缩点。第一问的答案就是缩点后入度为零的点的数量,而第二问则是入度为零和出度为零的点的数量的较大值。

    第一问很好理解,而第二问是为什么呢?

    我的理解是,第二问就是要让我们把缩点后的若干个强连通分量用一些边连起来,使它们形成一个强连通分量。那么显然每个点的入度和出度都不能为零。我们肯定是把出度为零的点连到入度为零的点上去。然后还剩下一些入度为零或出度为零的就单独搞。所以就是取较大值了。

    Code

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int n, tot, ind, top, cnt, tot1, tot2, res1, res2, rd[10005], cd[10005], col[10005], low[10005], dfn[10005], que[10005], vis[10005], hd[10005], to[5000005], nxt[5000005];
    
    int read()
    {
    	int x = 0, fl = 1; char ch = getchar();
    	while (ch < '0' || ch > '9') { if (ch == '-') fl = -1; ch = getchar();}
    	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    	return x * fl;
    }
    
    void add(int x, int y)
    {
    	tot ++ ;
    	to[tot] = y;
    	nxt[tot] = hd[x];
    	hd[x] = tot;
    	return;
    }
    
    void Tarjan(int x)
    {
    	low[x] = dfn[x] = ++ ind;
    	que[ ++ top] = x;
    	vis[x] = 1;
    	for (int i = hd[x]; i; i = nxt[i])
    	{
    		int y = to[i];
    		if (!dfn[y])
    		{
    			Tarjan(y);
    			low[x] = min(low[x], low[y]);
    		}
    		else if (vis[y]) low[x] = min(low[x], dfn[y]);
    	}
    	if (low[x] == dfn[x])
    	{
    		cnt ++ ;
    		int now = -1;
    		do
    		{
    			now = que[top -- ];
    			col[now] = cnt;
    			vis[now] = 0;
    		} while (now != x);
    	}
    	return;
    }
    
    int main()
    {
    	n = read();
    	for (int i = 1; i <= n; i ++ )
    	{
    		while (1)
    		{
    			int x = read();
    			if (!x) break;
    			add(i, x);
    		}
    	}
    	for (int i = 1; i <= n; i ++ )
    		if (!dfn[i])
    			Tarjan(i);
    	for (int x = 1; x <= n; x ++ )
    	{
    		for (int i = hd[x]; i; i = nxt[i])
    		{
    			int y = to[i];
    			if (col[x] != col[y])
    			{
    				add(col[x], col[y]);
    				rd[col[y]] ++ ;
    				cd[col[x]] ++ ;
    			}
    		}
    	}
    	for (int i = 1; i <= cnt; i ++ )
    	{
    		tot1 += (!rd[i]);
    		tot2 += (!cd[i]);
    	}
    	res1 = tot1; res2 = max(tot1, tot2);
    	printf("%d\n%d\n", res1, res2);
    	return 0;
    }