poj 1236 Network of Schools

本文介绍了一种解决特定图论问题的方法,即如何确定至少从多少个节点出发才能遍历整个有向图的所有节点,以及最少需要添加多少条边使图成为强连通图。通过将图中的强连通分量压缩成单个节点,转化为有向无环图(DAG),进而求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意: 给出一个有向图,问1: 至少从几个点出发,可以遍历所有的点。 2: 至少添几条边可以可以是图强连通。 

将图中的强连通分量缩点后,成一个 DAG(有向无环图); 图中 入度为0的点是无法通过其他点到达的,且图中从所有入度为0的点出发定能到达图中所有的点,因为其他点入度不为0。所以第一问答案就是入度为0点的个数。 

2: 及入度为0点a,出度为0点b . 强连通图是由若干个环组成的。所以对于入度为0 一条路径的重点必然是出度为0,将入度为0点和出度为0点链接起来,对于剩余的出度为0 或者入度为0的点,我们需要再加边将其加入图中的环内。 ans= max(a,b);明显 ans1>=1,ans2>=0,当图为一个强连通时要特判。 

#include<stack>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<iostream>
using namespace std;
const int maxn = 105*2;
int lowlink[maxn];
int pre[maxn];
int sccno[maxn];
stack<int>s;
vector<int>g[maxn];
int n;
int G[maxn][maxn];
int in[maxn];
int out[maxn];
int scc_cnt  = 0;
int dfs_clock=0;
void dfs(int u)
{
    pre[u] = lowlink[u] = ++dfs_clock;
    s.push(u);
    for(int i = 0; i<g[u].size(); i++)
    {
        int v = g[u][i];
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u] = min(lowlink[u],pre[v]);
        }
    }
    if(lowlink[u]==pre[u])
    {
        scc_cnt++;
        for(;;)
        {
            int x = s.top();
            s.pop();
            sccno[x] = scc_cnt;
            if(x==u)break;
        }
    }
}
void find_scc(int n)
{

    dfs_clock = scc_cnt = 0;
    memset(sccno,0,sizeof(sccno));
    memset(pre,0,sizeof(pre));
    for(int i = 1; i<=n; i++)
    {
        if(!pre[i])dfs(i) ;
    }
}
void work()
{
    memset(G,0,sizeof(G));
    while(!s.empty())s.pop();
    find_scc(n);
    for(int i = 1; i<=n; i++)
    {
        for(int j = 0; j<g[i].size(); j++)
        {
            int v = g[i][j];
            if(sccno[i]!=sccno[v])
            {
                G[sccno[i]][sccno[v]] = 1;
            }
        }
    }
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    for(int i = 1; i<=n; i++)
    {
        for(int j = 1; j<=n; j++)
        {
            if(G[i][j])
            {
                in[j]++;
                out[i]++;
            }
        }
    }
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        int x;
        for(int i = 1; i<=n; i++)
            g[i].clear();
        for(int i = 1; i<=n; i++)
        {
            while(1)
            {
                scanf("%d",&x);
                if(!x)break;
                g[i].push_back(x);
            }
        }
        work();

        int ans1 = 0;
        int ans2 = 0;
        for(int i = 1; i<=scc_cnt; i++)
        {
            if(in[i]==0)
                ans1++;
            if(out[i]==0)
                ans2++;
        }
        if(scc_cnt==1)
        {
            printf("1\n0\n");
            continue; 
        }
        cout<<ans1<<"\n"<<max(ans1,ans2)<<endl;
    }
    return  0; 
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值