HDU 4635 Strongly connected(图论)

如果有孤立的点,则把其他的点连成完全图。然后从该点向每一个点连一条有向边。总共(n-1)*(n-1) 条。

如果没有孤立的点,尽量找点数最小的强连通,且这个强连通只有向外的有向边,或者只有向里的有向边。把这些点练成完全图。其他的点也连成完全图。最后从这些点,分别向其他的点连有向边。设两个完全图的点数为n,m则总边数为n*(n-1)+m*(m-1);从一个完全图,指向另一个完全图的边数(n*m);

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <string>
#define LL long long
#define DB double
#define SF scanf
#define SI(a) scanf("%d",&a)
#define SD(a) scanf("%lf",&a)
#define PF printf
#define MM(a,b) memset(a,b,sizeof(a))
#define N 100009
#define bug cout<<"bug"<<endl
using namespace std;
int n,m;
int dfn[N],low[N],ind,col[N],color;
bool post[N];
stack<int> S;
vector<int>L[N];
void tarjan(int k){
    dfn[k] = low[k] =ind++;
    post[k] = true;
    S.push(k);
    for(int i=0;i<(int)L[k].size();i++){
        int to = L[k][i];
        if(!dfn[to]){
            tarjan(to);
            low[k] = min(low[k],low[to]);
        }else if(post[to]&&low[k]>dfn[to]){
            low[k] = dfn[to];
        }
    }
    if(dfn[k]==low[k]){
        color++;int i;
        for(i=S.top(),S.pop();i!=k;i=S.top(),S.pop())
        {
            col[i] = color; post[i] = false;
        }
        col[i]=color,post[i] = false;
    }
}

struct LLL{
    int l,r;
} link[N];
int in[N],ou[N];
int num[N];
LL solve()
{
    for(int i=1;i<=n;i++)
    if(dfn[i]==0)
    tarjan(i);
  //  for(int i=1;i<=n;i++) cout<<col[i]<<" ";cout<<endl;
    if(color==1) return -1;
    memset(in,0,sizeof(in));
    memset(ou,0,sizeof(ou));
    for(int i=0;i<m;i++)
    {
        if(col[link[i].l]==col[link[i].r])continue;
        ou[col[link[i].l]]++;
        in[col[link[i].r]]++;
    }
    memset(num,0,sizeof(num));
    for(int i=1;i<=n;i++)
    num[col[i]]++;
    LL ans = -1;
    for(int i=1;i<=color;i++)
    {
        if(in[i]==0||ou[i]==0)
        {
            int a = num[i],b = n-num[i];
            if(a==1||b==1)
            return 1ll*(n-1)*(n-1)-m;
            ans = max(1ll*a*(a-1)+1ll*b*(b-1)+1ll*a*b-m,ans);
        }
    }return ans;
}
int main()
{
   
    int T=1,cas;SF("%d",&cas);
    while(cas--)
    {
        SF("%d%d",&n,&m);
        memset(dfn,0,sizeof(dfn));
        ind = 1;color = 0;
        for(int i=0;i<=n;i++) L[i].clear();
        int a,b;
        for(int i=0;i<m;i++)
        {
            SF("%d%d",&a,&b);
            link[i].l = a;
            link[i].r = b;
            L[a].push_back(b);
        }
        cout<<"Case "<<T<<": "<<solve()<<endl;
        T++;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值