给一个图,问最多加几条边可以让他依然不变成强连通图。如果已经强连通输出-1
反向思路,对于一个完全连通图如何去除 k 条边 使得其变成非连通图。
那么 很显然, 我们需要找一个在原图基础上点数最小的联通块,当然这个联通块必须得没有入度或者出度,这样才能便于我们舍弃这个联通块,之后只要去除这个联通块和外界的入路或者出路就好了。。。最后结果减去m,,以下AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=1e5+5;
vector<int>v[maxn];
int stk[maxn],top,color,cnt;
int dfn[maxn],low[maxn];
int nod[maxn],col[maxn];
bool instk[maxn];
int in[maxn],ot[maxn];
inline void tarjan(int s)
{
dfn[s] = low[s] = ++cnt;
instk[s] = true;
stk[++top] = s;
for(int i=0;i<v[s].size();i++)
{
int t = v[s][i];
if(!dfn[t])
{
tarjan(t);
low[s] = min(low[s], low[t]);
}
else if(instk[t]) low[s] = min(dfn[t], low[s]);
}
if(dfn[s] == low[s])
{
color ++;
do{
int t = stk[top];
instk[t] = false;
col[t] = color;
nod[color]++;
}while(stk[top--]!=s);
}
}
inline void init(int n)
{
memset(in, 0, sizeof in);
memset(ot, 0, sizeof ot);
memset(stk, 0, sizeof stk);
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(col, 0, sizeof col);
memset(nod, 0, sizeof nod);
memset(instk, false, sizeof instk);
color = 0; top = 0; cnt = 0;
for(int i=0;i<=n;i++)v[i].clear();
}
int main()
{
int t; cin>>t;
int cas = 1;
while(t--)
{
int n,m; cin>>n>>m;
init(n);
for(int i=1;i<=m;i++)
{
int a,b; cin>>a>>b;
v[a].push_back(b);
}
for(int i=1;i<=n;i++)
if(!dfn[i])tarjan(i);
if(color == 1)
{
printf("Case %d: -1\n",cas++);
continue;
}
for(int s=1;s<=n;s++)
for(int i=0;i<v[s].size();i++)
{
int t = v[s][i];
if(col[s] != col[t])
{
ot[col[s]] ++;
in[col[t]] ++;
}
}
int minv = 0x3f3f3f3f;
/*cout<<"----"<<endl;
for(int i=1;i<=color;i++)
cout<<in[i]<<' '<<ot[i]<<endl;
cout<<"----"<<endl;*/
for(int i=1;i<=color;i++)
{
if(in[i]==0 || ot[i]==0)
{
minv = min(minv, nod[i]);
}
}
//cout<<minv<<endl;
int ans = n*(n-1) - m ;
ans -= minv*(n-minv);
printf("Case %d: %d\n",cas++, ans);
}
return 0;
}