Strongly connectedTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5179 Accepted Submission(s): 2058 Problem Description Give a simple directed graph with N nodes and M edges. Please tell me the maximum number of the edges you can add that the graph is still a simple directed graph. Also, after you add these edges, this graph must NOT be strongly connected.
Input The first line of date is an integer T, which is the number of the text cases.
Output For each case, you should output the maximum number of the edges you can add.
Sample Input 3 3 3 1 2 2 3 3 1 3 3 1 2 2 3 1 3 6 6 1 2 2 3 3 1 4 5 5 6 6 4
Sample Output Case 1: -1 Case 2: 1 Case 3: 15
Source |
给出一个有向图,问是否强连通,强连通输出-1,否则求加最多的边,无重复边和自环,使得其还是不强连通。
假设我们现在进行缩点之后得到一些强连通块,将点数最少的X块单独拿出来,其他的合并为Y块。
那么此时可以有X*(X-1) X块强连通最多边+Y*(Y-1) Y块强连通最多边+X*Y X的每一个点向Y连一条边。此时是不是强连通的最多边,然后减去已经有的M,即为所求。
X*(X-1)+Y*(Y-1)-X*Y-M=N*N-N-X*Y-M 。所以要求X*Y最小值,X+Y=N,那么X 与 Y相差最大时符合条件。所以选择一个入度或出度等于0的且点最少的那个强连通块作为X。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<queue>
#define ll long long
using namespace std;
int dx[2]= {0,1};
int dy[2]= {1,0};
const int INF=99999999;
const int MAXN = 100000+66;
const int MAXM = 100000+66;
struct Edge
{
int from,to,next;
} e[MAXM];
int dfn[MAXN],low[MAXN],head[MAXN],link[MAXN],visx,tot,tot_edge;
int n,nn,m,cnt,belong[MAXN],in[MAXN],out[MAXN],a[MAXN],sum[MAXN];
bool exist[MAXN];
void PrePare()
{
cnt=0;
visx=0;
tot=0;
memset(dfn,-1,sizeof dfn );
memset(low,-1,sizeof low );
memset(head,0,sizeof head );
memset(link,0,sizeof link );
memset(belong,0,sizeof belong );
memset(exist,0,sizeof exist );
memset(sum,0,sizeof sum );
memset(in,0,sizeof in );
memset(out,0,sizeof out );
}
void Add_Edge(int u,int v,int *head)
{
e[++tot].to=v;
e[tot].from=u;
e[tot].next=head[u];
head[u]=tot;
}
stack<int> st;
void Tarjan(int u)
{
dfn[u]=low[u]= ++visx;
st.push(u);
exist[u]=true;
for(int i=head[u]; i; i=e[i].next)
{
int v=e[i].to;
if(dfn[v]==-1)
{
Tarjan(v);
low[u]=min(low[v],low[u]);
}
else if(exist[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
++cnt;//强连通点的个数
while(1)
{
int v=st.top();
st.pop();
exist[v]=0;
belong[v]=cnt;//v这个
//sum[cnt]+=a[v];//看这个缩点的权值
if(v==u)
break;
}
}
}
void new_Map()
{
for(int i=1; i<=n; i++)
{
sum[belong[i]]++;
for(int j=head[i]; j; j=e[j].next)
{
int v=e[j].to;
if(belong[i]!=belong[v])
{
in[belong[v]]++;
out[belong[i]]++;
}
}
}
}
ll solve()
{
if(cnt==1)
{
return -1;
}
else
{
new_Map();
int ans=0;
//
int left=100000+1;
for(int i=1; i<=cnt; i++)
{
if(in[i]==0||out[i]==0)
{
if(sum[i]<left)
{
left=sum[i];
}
}
}
return (ll)(n*n-n-left*(n-left)-m);
}
}
int main()
{
int t;
scanf("%d",&t);
int num=0;
while(t--)
{
scanf("%d%d",&n,&m);
nn=n;
PrePare();
for(int i=1; i<=m; i++)
{
int u,v;
scanf("%d %d",&u,&v);
Add_Edge(u,v,head);
}
for(int i=1; i<=n; i++)
if(dfn[i]==-1)
Tarjan(i);//缩点
printf("Case %d: %lld\n",++num,solve());
}
return 0;
}