tarjan算法(五)

省赛前最后三个星期,我感觉我还能抢救一下······

这次关于tarjan算法还有最后一点,之前对于tarjan算法的实现都是基于无向图的,但是对于有向图的tarjan算法有一个地方有些不同。在通过后向边对low[p]进行更新时,无向图是通过判读v是否是u的父亲节点来判断的,如果是则不更新,不是就更新,这是由于我们把一条无向边当作两条有向边来处理时的特殊情况,虽然u到v是可以到达的,但是那条边已经走过了,所以不能再通过他来判段强连通性,但是对于有向图中每一条边都是一条独立的边,不存在已经走过的情况,所以是可以更新的,其次同样的道理,无向图只要通过后向边对low[p]进行更新了,那么他们就必定有两条边可以互相到达,但是对于有向图,虽然从u可以到达v,但是却不一定能从v到达u,所以在进行后向图更新时,要确定v在栈内,即v可以到达u才进行更新····具体画个图就明白了·····我的语言表达能力实在行啊

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

题目大意:给你一个简单有向图,问这个图最多能加多少条边,使它还是一个不连通的简单图

题解:我们可以发现,完全图的边是最多的,但是完全图是连通的,那么我们就要在完全图的基础上去除一些边使得图的连通分量增加,而很明显,当连通分量变成两个的时候是最理想的时候,那么我们的问题就变成了增加多少条边可以让这个图变成只有两个强连通分量,现在我们假设两个强连通分量为X,Y;里面的节点数量为x,y,那么x+y=n,而且每个强连通分量都是一个完全图,而且两个连通分量间的边的个数是x*y,即每个X里面的点都有一条到Y内点的边,而内部的边分别是x*(x-1)和y*(y-1),所以总的增加的边数就是x*(x-1)+y*(y-1)+x*y-m,对给定图的每个出度或者入度为零的连通分量都进行计算,最后求出最大值即可

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define Maxn 100005

int dfn[Maxn],low[Maxn],cnt[Maxn],sum[Maxn];
int in[Maxn],out[Maxn];
int sta[Maxn],insta[Maxn];
int top;
int head[Maxn],u[Maxn],v[Maxn],_next[Maxn];

int nu,num,c,m,n;
long long Max;
void into(){
	memset(dfn,0,sizeof(dfn));
	memset(cnt,0,sizeof(cnt));
	memset(head,-1,sizeof(head));
	memset(sum,0,sizeof(sum));
	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	memset(insta,0,sizeof(insta));
	nu=0;
	num=0;
	c=0;
	Max=0;
	top=0;
}

void tarjan(int k,int fa){
	dfn[k]=low[k]=++num;
	sta[top++]=k;
	insta[k]=1;
	for(int i=head[k];i!=-1;i=_next[i]){
		int e=v[i];
		if(!dfn[e]){
			tarjan(e,k);
			low[k]=min(low[e],low[k]);
		}
		else if(insta[e])low[k]=min(low[k],dfn[e]); 
	}
	if(dfn[k]==low[k]){
		nu++;
		int a;
		do{
			a=sta[--top];
			cnt[a]=nu;
			insta[a]=0;
			sum[nu]++;
		}while(a!=k);
	}
}

void add(int s,int t){
	u[c]=s;
	v[c]=t;
	_next[c]=head[s];
	head[s]=c++;
}
void jud(int s,int t){
	if(cnt[s]!=cnt[t]){
		in[cnt[t]]++;
		out[cnt[s]]++;
	}
}

int main(){
	int T;
	scanf("%d",&T);
	for(int tt=1;tt<=T;++tt){
		into();
		scanf("%d%d",&n,&m);
		for(int i=0;i<m;i++){
			int s,t;
			scanf("%d%d",&s,&t);
			add(s,t);
		}
		for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1);
		printf("Case %d: ",tt);
		if(nu==1) {
			printf("-1\n");
			continue;
		} 
		for(int i=0;i<c;i++) jud(u[i],v[i]);
		for(int i=1;i<=nu;i++){
			if(in[i]==0||out[i]==0){
				long long re=sum[i];
				Max=max(Max,re*(re-1)+(n-re)*(n-re-1)+re*(n-re)-m);
			}
		}
		printf("%I64d\n",Max);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值