浏览器标题切换
浏览器标题切换end

POJ1236 - Network of Schools - 强连通分量求缩点 - Tarjan模板题

题意

要求我们输出:

1、至少给几个点传递消息,才能保证所有消息传遍整个图;

2、至少添加几条边,才能使任意选择一个点,消息都能传遍整个图。

思路

强连通模板题。

第一问:强连通分量缩点之后有几个入度为0的点。

第二问:首先我们画个图,就能发现只要把入度为0的点直接连一条边到入度为0的点上,就可以形成一个环,所以答案是:max(入度为0的点,出度为0的点)。

3、注意一下特判,如果SCC只有一个,输出0即可。

AC代码

#include<stdio.h>
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=110;

int n,m,tot,num,countt,top,head[10*N];
int in[N],out[N],low[N],dfn[N],co[N],st[N],si[N];
bool book[N][N];

struct node
{
    int nextt,v;
} e[N*N*10];

void add(int u,int v)
{
    tot++;
    e[tot].nextt=head[u];
    head[u]=tot;
    e[tot].v=v;
}

void tarjan(int u)
{
    //top=0;
    dfn[u]=low[u]=++num;
    st[++top]=u;//入栈
    for(int i=head[u]; i!=-1; i=e[i].nextt)
    {
        int v=e[i].v;
        if(dfn[v]==0)
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(co[v]==0)
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        co[u]=++countt;//countt是连通分量个数
        ++si[countt];
        while(st[top]!=u)
        {
            ++si[countt];
            co[st[top--]]=countt;
        }
        --top;//出栈
    }
}

void init()
{
    countt=num=top=0,tot=-1;
    memset(head,-1,sizeof(head));
    memset(dfn,0,sizeof(dfn));
    memset(co,0,sizeof(co));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    memset(book,0,sizeof(book));
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1; i<=n; i++)
        {
            while(1)
            {
                int x;
                scanf("%d",&x);
                if(x==0)
                    break;
                add(i,x);
                book[i][x]=1;
            }
        }
        for(int i=1; i<=n; i++)
        {
            if(dfn[i]==0)
                tarjan(i);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                if(book[i][j]&&(co[i]!=co[j]))//说明点i可以到j&&i和j不在同一个连通分量里面
                {
                    out[co[i]]++;
                    in[co[j]]++;
                }
            }
        }
        int inn=0,outt=0;
        for(int i=1; i<=countt; i++)
        {
            if(out[i]==0)
                outt++;
            if(in[i]==0)
                inn++;
        }
        if(countt==1)//特判
        {
            printf("1\n");
            printf("0\n");
        }
        else
        {
            //至少给几个点传递消息,才能保证所有消息传遍整个图
            printf("%d\n",inn);//输出入度为0的个数

            //至少添加几条边,才能使任意选择一个点,消息都能传遍整个图
            int ans=max(outt,inn);//输出入度为0和出度为0的max
            printf("%d\n",ans);
        }
    }
    return 0;
}
posted @ 2020-09-22 20:40  抓水母的派大星  阅读(81)  评论(0编辑  收藏  举报