1. 程式人生 > >4635 Strongly connected

4635 Strongly connected

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.A simple directed graph is a directed graph having no multiple edges or graph loops. A strongly connected digraph is a directed graph in which it is possible to reach any node starting from any other node by traversing edges in the direction(s) in which they point.

Input

The first line of date is an integer T, which is the number of the text cases. Then T cases follow, each case starts of two numbers N and M, 1<=N<=100000, 1<=M<=100000, representing the number of nodes and the number of edges, then M lines follow. Each line contains two integers x and y, means that there is a edge from x to y.

Output

For each case, you should output the maximum number of the edges you can add. If the original graph is strongly connected, just output -1.

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

題意:給定一個圖,求在不成為強連通的條件下最多能新增多少條邊。如果本來就是連通圖,輸出-1.

思路:先用tarjan縮點。不成為強連通,只需要一個點被孤立(不能形成迴路),其他點全部連線。這個被孤立的點需要縮點中的點儘量少,且需要入度或者出度為零。假設被最少的縮點中有p個點,則其他可以任意連線的點為di=n-p。di個點一共可以連線di*(di-1)條邊,最少縮點中要只能進或則只能出(入度為零或出度為零)。所以最少縮點裡面的點也可以任意連線,總數為p*(p-1)。被孤立的點連線其他點(只進或只出),一共有p*n條,則總數為:di*(di-1)+p*(p-1)+p*n。然後減去題目給出的邊數m就是答案。

#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<stack>
#define M 100010
using namespace std;
struct path
{
    int to,nextt;
}A[M];
stack<int>q;
int head[M],DFN[M],LOW[M],book[M],re[M],in[M],out[M],sum[M];
int t,ph=0,n,m,x,y,tot,carry,indox;
void init()
{
    tot=carry=indox=0;
    memset(in,0,sizeof(in));
    memset(head,-1,sizeof(head));
    memset(book,0,sizeof(book));
    memset(DFN,-1,sizeof(DFN));
    memset(LOW,-1,sizeof(LOW));
    memset(out,0,sizeof(out));
    memset(sum,0,sizeof(sum));
    return ;
}
void add(int u,int v)
{
    A[tot].to=v;
    A[tot].nextt=head[u];
    head[u]=tot++;
    return ;
}
void tarjan(int u)
{
    int tem;
    DFN[u]=LOW[u]=++indox;
    book[u]=1;
    q.push(u);
    for(int i=head[u];i!=-1;i=A[i].nextt)
    {
        tem=A[i].to;
        if(DFN[tem]==-1)
        {
            tarjan(tem);
            LOW[u]=min(LOW[u],LOW[tem]);
        }
        else if(book[tem])
        {
            LOW[u]=min(LOW[u],DFN[tem]);
        }
    }
    if(DFN[u]==LOW[u])
    {
        ++carry;
        do
        {
            tem=q.top();
            q.pop();
            book[tem]=0;
            re[tem]=carry;
        }while(tem!=u);
    }
    return ;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        for(int i=1;i<=n;i++)
        {
            if(DFN[i]==-1)
                tarjan(i);
        }
        printf("Case %d: ",++ph);
        if(carry==1)
        {
            printf("-1\n");
            continue;
        }
        int v;
        for(int i=1;i<=n;i++)
        {
            sum[re[i]]++;
            for(int j=head[i];j!=-1;j=A[j].nextt)
            {
                v=A[j].to;
                if(re[i]!=re[v])
                {
                    in[re[v]]++;
                    out[re[i]]++;
                }
            }
        }
        int pan=0x3f3f3f3f,k;
        for(int i=1;i<=carry;i++)
        {
            if(pan>sum[i]&&(in[i]==0||out[i]==0))
            {
                pan=sum[i];
                k=i;
            }
        }
        int di=n-pan;
        int ans=di*(di-1)+di*pan-m+pan*(pan-1);
        printf("%d\n",ans);
    }
}