zoukankan      html  css  js  c++  java
  • [Luogu] P2812 校园网络【[USACO]Network of Schools加强版】

    (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
    %d
    ", res1, res2);
    	return 0;
    }
    
  • 相关阅读:
    ssh访问控制,多次失败登录即封掉IP,防止暴力破解
    经常用到的一些命令行
    自定义控件
    委托线程三部曲(引用)
    关于委托
    三个调用的例子(转)
    同一网段的两台电脑通信(转)
    SOCKET原理(转载)
    C#winform和百度API互动-----之JS读取中C#中的函数
    C#winform和百度API互动-----之读取中js的参数
  • 原文地址:https://www.cnblogs.com/andysj/p/13917584.html
Copyright © 2011-2022 走看看