HDU4635 Strongly connected(tarjan縮點+思路)

Strongly connected

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3476    Accepted Submission(s): 1402


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.
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

首先對於找最多的邊,可以逆向考慮一下,先把圖補滿(即任意兩點之間都有一條邊)刪除最少的邊,對於原本已經有的邊肯定是不能刪的,首先在滿的基礎上減去原有的m條邊,並用這m條邊縮點,此時塊與塊之間的關係有了。然後只需要找出個點數最少的塊,刪去他與剩下所有塊裏的點之間的一條邊即可,此時只能由點數少的塊到點數大的塊或點數大的塊到點數小的塊。因爲x+y是個固定值時,x和y的差距越大,x*y越小。故此時刪去邊最少。

會有一個問題,這樣刪的時候會不會把原來的m條邊刪去?

其實是不會的,因爲刪邊所用的圖是由m條邊縮點後的圖,這m條邊的關係只可能是每個塊的內部與塊與塊之間,我們刪去的是 點數最少塊裏的點與 其他所有塊的點之間的一條邊,每個塊的點與另一個塊之間依然相連至少一條邊,而原本m條邊,每個塊的點與另一個塊的點之間最多也只有一條邊(兩條邊就連通了,縮點會直接縮到一個塊裏)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int N=200005;
int low[N],dfn[N],dfs_num,vis[N];//tarjan
int tot,first[N];//鄰接表
int col_num,top,block[N];//染色
int st[N];//染色與點雙聯通
int id[N],od[N],num[N];
struct edge
{
    int v,next;
} e[N*20];
void init(int n)
{
    mem(first,-1);
    mem(dfn,0);
    mem(low,0);
    mem(vis,0);
    mem(id,0);
    mem(od,0);
    mem(num,0);
    mem(st,0);
    tot=0,col_num=0,dfs_num=0,top=0;

}
void add(int u,int v)
{
    e[tot].v=v;
    e[tot].next=first[u];
    first[u]=tot++;
}
void dyeing(int u)//染色
{
    int v;
    if(low[u]==dfn[u])
    {
        ++col_num;
        do
        {
            v=st[--top];
            block[v]=col_num;
            num[col_num]++;
            vis[v]=0;
        }
        while(v!=u);
    }
}
void dfs(int u,int fa)
{
    low[u]=dfn[u]=++dfs_num;
    vis[u]=1;
    st[top++]=u;
    for(int i=first[u]; ~i; i=e[i].next)
    {
        int v=e[i].v;
        if(!dfn[v])
        {
            dfs(v,u);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
            low[u]=min(low[u],dfn[v]);
    }
    dyeing(u);//染色
}
void solve(int n,int m)
{
    for(int i=1; i<=n; i++)
    {
        if(!dfn[i])dfs(i,-1);
    }
    if(col_num==1)
    {
        puts("-1");
        return;
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=first[i]; ~j; j=e[j].next)
        {
            int v=e[j].v;
            if(block[i]==block[v])continue;
            od[block[i]]++;
            id[block[v]]++;
        }
    }
    ll ans=n*(n-1)-m;
    int minn=inf;
    for(int i=1;i<=col_num;i++)
        {
            if(!id[i]||!od[i])
            minn=min(minn,num[i]);
        }
        ans-=minn*(n-minn);
    printf("%lld\n",ans);
}
int main()
{
    int t,n,m,x,y,q=0;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        init(n);
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        printf("Case %d: ",++q);
        solve(n,m);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章