hdu 4635 Strongly connected 強連通

/*
hdu 4635 Strongly connected 強連通
題意:給一個簡單(無重邊,無自環:就是自己直接指向自己的邊)有向圖,
若是強連通的,就輸出-1
否則輸出可以最多加多少條邊還是非強連通的;

加完邊的狀態就是,有兩個強連通塊兒(包含的點數分別是n,m),各自內部任意兩點之間都有兩條不同方向的邊,
兩個塊兒之間只有單方向的邊,另一個方向的邊是因爲保持非強連通犧牲掉的(數量是n*m),

n個點的強連通圖最多可以有n*(n-1)條邊,有m條已存在,n*m條被犧牲了,不可建,剩下的就是可見的,

對沒有入度或沒有出度的塊兒枚舉,使得n*m最小即可
*/
#include<stdio.h>
#include<stack>
using namespace std;
const int N=100000+10;
stack<int>s;  
int ret;  
struct node  
{  
    int v,next;  
} e[N];  
int ins[N],fang[N],head[N],low[N],belong[N];  
int ru[N],chu[N];  
int numd[N];
int n,m,yong;  
void tarjan(int k)  
{  
    int j,u;  
    fang[k]=low[k]=yong++;  
    ins[k]=1;  
    s.push(k);//強連通爲什麼要用棧?棧中其往上的都是可能和他是同一連通分量的,不可以訪問非棧上節點是他們不可能在同一連通分量上(訪問過而不在棧上,還可能是同一連通分量麼),若訪問 訪問過而不在棧上 的節點(不是同一連通分量,他們早已出棧,說明他們的根還是比較高的,對他沒有更新)  
    for(j=head[k];j;j=e[j].next)  
    {  
        u=e[j].v;  
        if(fang[u]==0)  
        {  
            tarjan(u);  
            if(low[u]<low[k])  
                low[k]=low[u];  
        }else if(ins[u]&&fang[u]<low[k])//u可能在上一路上已被訪問過,或者u就是k的祖先,他們一定是同一連通分量;與雙連通不同的是:他要求的是自己不越過自己,所以,即使他有回邊,早晚更新都是一樣;雙連通擔心的是他提前更新,導致他的孩子也提前更新,從而fang[本節點]>low[孩子]=low[本節點]=low[本節點的父節點]  
            low[k]=fang[u];  
    }  
    if(low[k]==fang[k])//其能探到的最低的不越過他自己,說明其以下是一個連通分量  
    {  
        ret++;  
        do{  
			j=s.top();  
			s.pop();  
			ins[j]=0;  
			belong[j]=ret;
        }while(j!=k);  
    }  
}  
void adde(int a,int b)
{
	e[yong].v=b;
	e[yong].next=head[a];
	head[a]=yong++;
}
int main()
{
	int t,ti,a,b,i,j;
	scanf("%d",&t);
	for(ti=1;ti<=t;++ti)
	{
		ret=0;  
        yong=1;  
		scanf("%d%d",&n,&m);  
		memset(head,0,sizeof(head));  
		for(i=0;i<m;++i)
		{
			scanf("%d%d",&a,&b);
			adde(a,b);
		}
		yong=1;  
        memset(ins,0,sizeof(ins));  
        memset(fang,0,sizeof(fang));  
        for(i=1;i<=n;i++)  
		{
			if(fang[i]==0)  
			{
				tarjan(i);  
			}
		}
		if(ret==1)
		{
			printf("Case %d: -1\n",ti);
			continue;
		}
		memset(chu,0,sizeof(chu));  
		memset(ru,0,sizeof(ru));  
		memset(numd,0,sizeof(numd));  
		for(i=1;i<=n;i++)  
		{
			numd[belong[i]]++;
			int index=head[i];
			for(;index;index=e[index].next)
			{
				j=e[index].v;
				if(belong[i]!=belong[j])
				{
					chu[belong[i]]++;  
					ru[belong[j]]++;  
				}
			}
		}
		__int64 sheng=1;
		sheng=sheng*n*(n-1);
		sheng=sheng-m;
		__int64 xiao=0x7fffffffffffff;
		__int64 tem;
		for(i=1;i<=ret;++i)
		{
			if(chu[i]==0||ru[i]==0)
			{
				tem=((__int64)numd[i])*(n-numd[i]);
				if(tem<xiao)
				{
					xiao=tem;
				}
			}
		}
		sheng=sheng-xiao;
		printf("Case %d: %I64d\n",ti,sheng);
	}
	return 0;
}

發佈了202 篇原創文章 · 獲贊 9 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章