P2746 [USACO5.3]校园网Network of Schools

第二个点想不出来。。。


题目给你一个有向图,然后问你两个问题:

  1. 至少标记几个点,才能使所有点都被标记。

  2. 还需要添加几条边,才能使整个图都连通。

其实像考tarjan的题目,大多都跟入度和出度相关联。就像那道“受崇拜的牛”。

直接用tarjan算法进行缩点,得到一个DAG。

有了一个DAG后就可以用入度和出度来讨论一些特定的性质。

第一个问题:发现只要在DAG中,标记拓扑序在最前头的那些点,整个图都会被标记。

而这些点的特征就是:入度为0。

所以统计一下新图中入度为0的点有多少个就可以了。

第二个问题:如果要还要添加边,那么缩完的图就肯定不止一个点。

想要都连通,就要将一个路径的终点和另一个路径的起点相连接

一条路径的终点的特征?出度为0。起点特征?入度为0。

那么就用最少的边将所有的0出度点和0入度点连接起来。

最少多少?是它们的最大值。

但是注意一个特判:

如果这个图一开始就所有点连通的话,缩点得到的有一个点。

如果按照上面的做法的话,第二个答案会是1,但实际不用添加任何边。

所以特判一下就可以了。

代码:

#include<cstdio>
#include<algorithm>
const int maxn = 105;
struct Edges
{
    int next, to;
} e[maxn * maxn], e2[maxn * maxn];
int head[maxn], tot;
int head2[maxn], tot2;
int dfn[maxn], low[maxn], dtot;
bool vis[maxn];
int stack[maxn], top;
int color[maxn], ctot;
int indegree[maxn], outdegree[maxn];
int n;
bool b[maxn][maxn];
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-') s = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return s * ans;
}
void link(int u, int v)
{
    e[++tot] = (Edges){head[u], v};
    head[u] = tot;
}
void link2(int u, int v)
{
    e2[++tot2] = (Edges){head2[u], v};
    head2[u] = tot2;
}
void tarjan(int u)
{
    dfn[u] = low[u] = ++dtot;
    stack[++top] = u; vis[u] = true;
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u] = std::min(low[u], low[v]);
        }
        else if(vis[v]) low[u] = std::min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u])
    {
        ctot++;
        while(stack[top] != u)
        {
            int x = stack[top--]; vis[x] = false;
            color[x] = ctot;
        }
        int x = stack[top--]; vis[x] = false;
        color[x] = ctot;
    }
}
int main()
{
    n = read();
    for(int i = 1; i <= n; i++)
    {
        int temp;
        while(2333)
        {
            temp = read();
            if(temp == 0) break;
            link(i, temp);
        }
    }
    for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i);
    for(int u = 1; u <= n; u++)
    {
        for(int i = head[u]; i; i = e[i].next)
        {
            int v = e[i].to;
            if(color[u] != color[v] && !b[color[u]][color[v]])
            {
                link2(color[u], color[v]);
                indegree[color[v]]++;
                outdegree[color[u]]++;
                b[color[u]][color[v]] = true;
            }
        }
    }
    int ans1 = 0, ans2 = 0;
    for(int i = 1; i <= ctot; i++) 
    {
        if(indegree[i] == 0) ans1++;
        if(outdegree[i] == 0) ans2++;
    }
    printf("%d\n%d\n", ans1, ctot == 1 ? 0 : std::max(ans1, ans2));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Garen-Wang/p/9369010.html
今日推荐