您的位置:首页 > 其它

HDU 4635 Strongly connected (有向图的强连通分量)

2016-06-20 21:04 489 查看

Strongly connected

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)


[align=left]Problem Description[/align]
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.


[align=left]Input[/align]
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.

[align=left]Output[/align]
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.

[align=left]Sample Input[/align]

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

[align=left]Sample Output[/align]

Case 1: -1
Case 2: 1
Case 3: 15

题解
问:最多加多少条边,使得原图不是强连通图
可以反向思考,假设原图已满边,即sum=n*(n-1),减去多少条边使其不是强连通图
直接加边sss=n*(n-1)-m;
用Tarjan求出强连通分量并缩点,将缩好的点分为两部分,一部分到另一部分没有边(即这个点的入度或出度为0),然后用sss减去这两部分能构成的变数。
假设第i个强连通分量有num[i]个点,则它与另一半的图所能连接的边数为num[i]*(n-num[i]),求这个的最小值,减去就行了。
代码

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

const int MAXN = 100000+100;
/*
* Tarjan算法
* 复杂度O(N+M)
*/
struct Edge{
int to,next;
}edge[MAXN];
int head[MAXN],tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];//Belong数组的值是1~scc
int Index,top;
int scc;//强连通分量的个数
bool Instack[MAXN];
int num[MAXN];//各个强连通分量包含点的个数,数组编号1~scc

void init()
{
tot=0;
memset(head,-1,sizeof(head));
}

void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}

void Tarjan(int u)
{
int v;
Low[u]=DFN[u]=++Index;
Stack[top++]=u;
Instack[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].to;
if(!DFN[v]){
Tarjan(v);
if(Low[u]>Low[v]) Low[u]=Low[v];
}
else if(Instack[v]&&Low[u]>DFN[v])
Low[u]=DFN[v];
}
if(Low[u]==DFN[u]){
scc++;
do{
v=Stack[--top];
Instack[v]=false;
Belong[v]=scc;
num[scc]++;
}
while(v!=u);
}
}

void solve(int n)
{
memset(DFN,0,sizeof(DFN));
memset(Instack,false,sizeof(Instack));
memset(num,0,sizeof(num));
Index=top=scc=0;
for(int i=1;i<=n;i++)
if(!DFN[i])
Tarjan(i);
}

int in[MAXN],out[MAXN];

int main()
{
int T;
int iCase=0;
scanf("%d",&T);
while(T--){
iCase++;
init();
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
}
solve(n);
if(scc==1){
printf("Case %d: -1\n",iCase);
continue;
}
for(int i=1;i<=scc;i++){
in[i]=0;
out[i]=0;
}
for(int u=1;u<=n;u++){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(Belong[u]==Belong[v]) continue;
out[Belong[u]]++;
in[Belong[v]]++;
}
}
long long sss=(long long)n*(n-1)-m;
long long ans=0;
for(int i=1;i<=scc;i++){
if(in[i]==0||out[i]==0)
ans=max(ans,sss-(long long)num[i]*(n-num[i]));
}
printf("Case %d: %lld\n",iCase,ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: