2017西安网赛一个题

题意给你一个图,然后问你,加入多少条边,能使这个图构成成一个强连通分量
题解主要是我不会强连通分量,后来学了一把,然后这个题就很好解决了,首先,把强连通分量缩成一个点,然后现在就成了一个dag,这个dag中,有入度,有出度的点,没有用,看只有入度,和只有出度的点。取个max就好了

//有向图强连通分量:分量中任何两点均可通过路径互达,缩点后成为一个DAG
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

const int MaxN = 50000, MaxM = 200000;

int T, n, m, all, Timetot, Scctot; 
int pre[MaxM + 5], last[MaxN + 5], other[MaxM + 5];
int pr[MaxM + 5], las[MaxN + 5], oth[MaxM + 5];
int dfn[MaxN + 5], low[MaxN + 5], col[MaxN + 5];
int ind[MaxN + 5], oud[MaxN + 5];
bool usedind[MaxN + 5], usedoud[MaxN + 5], usedused[MaxN + 5];
stack <int> sta;
vector <int> Scc[MaxN + 5];
map <pair<int, int>, bool> used;

void Build(int x, int y)
{
    pre[++all] = last[x];
    last[x] = all;
    other[all] = y;
}

void Init()
{
    all = -1; memset(last, -1, sizeof(last));
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        Build(u, v); 
    }
}

void Dfs_Scc(int x, int fa)
{
    dfn[x] = low[x] = ++Timetot;
    sta.push(x);    //强连通分量 存点不存边
    int ed = last[x], dr;
    while (ed != -1) {
        dr = other[ed];
        if (!dfn[dr]) {
            Dfs_Scc(dr, x);
            low[x] = min(low[x], low[dr]);
        }
        else if (!col[dr] && dfn[dr] < dfn[x]) {
            low[x] = min(low[x], dfn[dr]);
        }
        ed = pre[ed];
    }
    if (low[x] >= dfn[x]) { //强连通分量注意是while出来以后判
        Scc[++Scctot].clear();
        while (true) {
            int u = sta.top(); sta.pop();
            col[u] = Scctot;
            Scc[Scctot].push_back(u);
            if (u == x) break;
        }
    }
}

void rBuild(int x, int y)
{
    pr[++all] = las[x];
    las[x] = all;
    oth[all] = y;
    ind[x]++;
    oud[y]++;
}

void ReBuildGraph()
{
    used.clear();
    all = -1; memset(las, -1, sizeof(las)); //all用原来的,las也记得清成-1
    for (int i = 1; i <= n; i++) {
        int ed = last[i], dr;
        while (ed != -1) {
            dr = other[ed];
            if (col[i] != col[dr] && !used[make_pair(col[i], col[dr])]) {
                used[make_pair(col[i], col[dr])] = true;
                rBuild(col[i], col[dr]);
            }
            ed = pre[ed];
        }
    }
}

void Solve()
{
    Timetot = Scctot = 0;
    memset(dfn, 0, sizeof(dfn));    //dfn, low每次必须清空
    memset(low, 0, sizeof(low));
    memset(col, 0, sizeof(col));
    memset(ind, 0, sizeof(ind));
    memset(oud, 0, sizeof(oud));
    for (int i = 1; i <= n; i++) 
        if (!dfn[i]) Dfs_Scc(i, -1);
    ReBuildGraph();
    memset(usedused, 0, sizeof(usedused));
    int num = 0;
    for (int i = 1; i <= n; i++) {
        if (!usedused[col[i]]) {
            usedused[col[i]] = true;
            num++;
        }
    }
    memset(usedind, 0, sizeof(usedind));
    memset(usedoud, 0, sizeof(usedoud));
    int sum_ind = 0, sum_oud = 0;
    for (int i = 1; i <= n; i++) {
        if (ind[col[i]] == 0 && !usedind[col[i]]) {
            usedind[col[i]] = true;
            sum_ind++;
        }
        if (oud[col[i]] == 0 && !usedoud[col[i]]) {
            usedoud[col[i]] = true;
            sum_oud++;
        }
    }
    if (num == 1) printf("0\n");
    else printf("%d\n", max(sum_ind, sum_oud));
}

int main()
{
    scanf("%d", &T);
    for (int cas = 1; cas <= T; cas++) {
        Init();
        Solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值