poj1236 Network of Schools (Targan强连通图缩点)

第一道连通图题吧以此纪念下
题意:给一张有向无环图有两个任务

1.最至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
2.至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点

解题思路:
1. 求出所有强连通分量
2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。
3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少
4. 在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少
5. 怎么加边呢:两种 n :表示入度为0的个数,m:出度为0的个数 问题2的答案 为 max(n,m);

1.求强连通分量采用的是Targan算法
不懂的移步吧 https://www.byvoid.com/zhs/blog/scc-tarjan

/*===================================================
 * Author :     Uniontake
 * Email  :     mr.uniontake@gmail.com
 * File   :     A-poj1236-Network-of-Schools.cpp CPP
 * Creat Date : 2017-10-06 11:09:16
 * Do one thing at a time, and do well
===================================================*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <iomanip>
#define mem(a,x) memset(a,x,sizeof(a))
#define gcd(a,b) __gcd(a,b)
#define lowbit(x) (x&-x)
#define LL long long
#define MOD 1000000007
#define INF 0x3f3f3f3f
#define pi (acos(-1.0))
#define eps (1e-8)
using namespace std;
const int maxn = 110;
int n;           //num
int dfs_num;
int dfn[maxn];   //递归次序
int low[maxn];   //回溯堆栈中最早的节点
int sta[maxn];
bool vis[maxn];  //判断元素是否在堆栈中
int maze[maxn][maxn]; //邻接矩阵
int indegree[maxn],outdegree[maxn]; //出度入度
int color[maxn];
int colorsnum;
int top;
void Targan(int u)
{
    dfn[u] = low[u] = ++dfs_num;
    sta[top++] = u;
    vis[u] = true;
    for(int i=1;i<=n;i++) if(maze[u][i])
    {
        if(!dfn[i])
        {
            Targan(i);
            low[u] = min(low[u],low[i]);
        }
        else if(vis[i]) { low[u] = min(low[u],dfn[i]); }
    }
    if(dfn[u] == low[u])
    {
        colorsnum++;
        while(1)
        {
            int v = sta[--top];
            color[v] = colorsnum;
            vis[v] = false;
            if( v == u ) break;
        }
    }   
}
void init()
{
    top = 0;
    colorsnum = 0;
    dfs_num = 0;
    mem(color,0);
    mem(maze,0);
    mem(dfn,0);
    mem(sta,0);
    mem(low,0);
    mem(vis,false);
    mem(indegree,0);
    mem(outdegree,0);
}
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        int x;
        for(int i=1;i<=n;i++)
        {
            while(scanf("%d",&x))
            {
                if(!x) break;
                maze[i][x] = 1;
            }
        }
        for(int i=1;i<=n;i++) if(!dfn[i]) //图不是连通的
            Targan(i);
        if(colorsnum == 1)  //特判
        {
            printf("1\n0\n");
            continue;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++) if(maze[i][j] && color[i]!=color[j])
            {
                   outdegree[color[i]]++;
                   indegree[color[j]]++;
            }
        }
        int ans1,ans2;
        ans1 = ans2 = 0;
        for(int i=1;i<=colorsnum;i++)
        {
            if(!indegree[i]) ans1++;
            if(!outdegree[i]) ans2++;
        }
        printf("%d\n%d\n",ans1,max(ans1,ans2));
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值