HDU 4635 Strongly connected(强连通)

来源:互联网 发布:dia frampton知乎 编辑:程序博客网 时间:2024/06/06 00:55

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4635


题意:给你一个图, 若为强连通图,则输出-1,否则求出至多加上多少边使图仍是非强连通图.


思路:缩点后找出那些入度或出度为0的强连通分量,因为最多的加边情况就是使图变成两个强连通分量,一个入度为0,一个出度为0,这两个分量内部点互相指向,假设一个分量的点数为x,则另一个是n - x,故最多添边的情况便是x * (x - 1) + y * (y - 1) + x * y - m,枚举一下即可


#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <utility>#include <functional>using namespace std;const int N = 200010;const int M = 400010;struct edge{    int to, nxt;} e[M];int n, m, cnt, head[N];int dep, top, scc;int dfn[N], low[N], vis[N], sta[N], bel[N], in[N], out[N], sum[N];void add(int u, int v){    e[cnt].to = v;    e[cnt].nxt = head[u];    head[u] = cnt++;}void Tarjan(int u){    dfn[u] = low[u] = ++dep;    sta[top++] = u;    vis[u] = 1;    for(int i = head[u]; i != -1; i = e[i].nxt)    {        int v = e[i].to;        if(!dfn[v])        {            Tarjan(v);            low[u] = min(low[u], low[v]);        }        else            if(vis[v])            {                low[u] = min(low[u], dfn[v]);            }    }    int v;    if(dfn[u] == low[u])    {        scc++;        do        {            v = sta[--top];            bel[v] = scc;            sum[scc]++;            vis[v] = 0;        }        while(u != v);    }}void init(){    cnt = 0;    memset(head, -1, sizeof(head));}void solve(){    dep = top = scc = 0;    memset(dfn, 0, sizeof(dfn));    memset(low, 0, sizeof(low));    memset(vis, 0, sizeof(vis));    memset(bel, 0, sizeof(bel));    memset(sum, 0, sizeof(sum));    memset(in, 0, sizeof(in));    memset(out, 0, sizeof(out));    for(int i = 1; i <= n; i++)        if(!dfn[i])            Tarjan(i);    if(scc == 1)    {        puts("-1");        return ;    }    for(int u = 1; u <= n; u++)        for(int i = head[u]; i != -1; i = e[i].nxt)        {            int v = e[i].to;            if(bel[u] != bel[v])            {                out[bel[u]]++;                in[bel[v]]++;            }        }    long long ans = 0;    for(int i = 1; i <= scc; i++)        if(in[i] == 0 || out[i] == 0)        {            long long x = sum[i];            long long y = n - x;            ans = max(ans, x * (x - 1) + y * (y - 1) + x * y - m);        }    cout << ans << endl;}int main(){    int t;    scanf("%d", &t);    for(int ca = 1; ca <= t; ca++)    {        init();        printf("Case %d: ", ca);        scanf("%d%d", &n, &m);        for(int i = 0; i < m; i++)        {            int u, v;            scanf("%d%d", &u, &v);            add(u, v);        }        if(n == 1)        {            puts("-1");            continue;        }        solve();    }    return 0;}




0 0