tarjan——连通图

深有分析且学习到东西的好题,存一个:http://poj.org/problem?id=1236

总结一下:

1.环对A问,也就是最少起点遍历全图的影响,所以需要tarjan缩点成DAG。

2.题意误解了几次,倒不是说单词不认识,真·阅读理解——差。

3.具体分析我写在代码注释里了,很享受这种分析的过程。

另外贴一个分析的很好的博客:https://www.cnblogs.com/kuangbin/archive/2011/08/07/2130277.html

复制代码
//#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
#define N 2021
#define mt(x) memset(x, 0, sizeof x)
typedef long long ll;
void cn(ll x) { cout << x << endl; }
void cs(string x) { cout << x << endl; }
vector<int> vc[N];
int dfn[N], low[N], vis[N], cnt;
int st[N], top;
int col[N], tot;
int in[N], out[N];
/*
不需要实际建图
struct ii
{
    int to, next;
} mp[N];
int head[N], num;
void add(int x, int y)
{
    mp[++num].to = y;
    mp[num].next = head[x];
    head[x] = num;
}
*/
void tarjan(int x)
{
    dfn[x] = low[x] = ++cnt;
    st[++top] = x;
    vis[x] = 1;
    for (int i = 0; i < vc[x].size(); ++i)
    {
        int y = vc[x][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 (dfn[x] == low[x])
    {
        tot++;
        int y;
        do
        {
            y = st[top--];
            vis[y] = 0;
            col[y] = tot;
        } while (x != y);
    }
}
void solve()
{
    /*
    analyse:
    A:最少多少学校为起点,能到达所有学校
    B:最少添加多少list才能让所有学校连通

    A满足最少,每一个连通块看作一个单位,
    也即缩点之后的DAG图里,入度为0的数量即是A的答案

    B加边,,,
    想法是,将A问的起点学校数x,-1即为B的答案
    也就是将起点之间连接起来。。。
    也就是入度为0的数量-1即是B的答案

    误解了题意,,是说,从任意学校,都能连通
    也即应该是,每个连通块与另外连通块首尾相连
    也即,入度0和出度0的点相连
    怎么相连呢,
    n个入度0,m个出度0
    若n>m,则参照n连接
    若n<m,则参照m连接
    也即B答案为max(n,m)
    有个特殊情况是,只有一个强连通块时候,虽然有n,m,但是不需要加边,也就是0
    */
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
        int x;
        while (cin >> x && x)
        {
            vc[i].push_back(x);
        }
    }
    for (int i = 1; i <= n; ++i)
    {
        if (!dfn[i])
            tarjan(i);
    }
    for (int i = 1; i <= n; ++i) //建图DAG
    {
        for (int j = 0; j < vc[i].size(); ++j)
        {
            int y = vc[i][j];
            if (col[i] != col[y])
            {
                in[col[y]]++;
                out[col[i]]++;
            }
            //add(col[i], col[y]);不需要实际建图
        }
    }
    int inn=0,outt=0;
    for (int i = 1; i <= tot; ++i)
    {
        if(!in[i])inn++;
        if(!out[i])outt++;
    }
    if(tot==1)cout<<1<<'\n'<<0<<endl;
    else cout<<inn<<'\n'<<max(inn,outt)<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    solve();
    return 0;
}
复制代码

 

posted @   Renhr  阅读(45)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示