2017西安网赛一个题

来源:互联网 发布:关键词优化简易 编辑:程序博客网 时间:2024/04/28 13:34

题意给你一个图,然后问你,加入多少条边,能使这个图构成成一个强连通分量
题解主要是我不会强连通分量,后来学了一把,然后这个题就很好解决了,首先,把强连通分量缩成一个点,然后现在就成了一个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;}