Strongly connected HDU - 4635

Source

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

题意:
给一个 n 个节点,m 条边的有向图,求最大可以增加多少条边使得这个有向图仍然不是强连通
1≤n,m≤100000

定理:
“ 有向图中存在某点的入度或出度为零时,这张有向图不是强连通图 ”

解法:
该题一般采用逆向思维
定义题中所给图为G1,一个有n个点有向完全图G2
最多增加多少条边使得G1不是强连通最少删除多少条边使得G2不是强连通

上来先缩点
构造一个n个点的有向完全图,需要n*(n-1)条边
而已经给出了m条,故先删去m条,剩下n*(n-1) - m条边
枚举所有出度或入度为0的强连通分量 求出所含点数的最小值(minn)
最后结果即为n * (n - 1) - m - minn * (n - minn)

ACODE:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MX = 1e5 + 7;
const int INF = 0x3f3f3f3f;
vector<int>G[MX];
int n,m;
int t;
int cnt,DFN[MX],LOW[MX];
int col[MX],colnum[MX];
int in[MX],out[MX];
bool ins[MX];
stack<int>s;
void tarjan(int u)
{
     
	++t;
	DFN[u] = LOW[u] = t;
	s.push(u);
	ins[u] = true;
	int len = G[u].size();
	for(int i = 0;i < len;++i)
	{
     
		int v = G[u][i];
		if(DFN[v] == 0){
     
			tarjan(v);
			LOW[u] = min(LOW[v],LOW[u]);
		}
		else if(ins[v]){
     
			LOW[u] = min(LOW[u],DFN[v]);
		}
	}

	if(DFN[u] == LOW[u])
	{
     
		cnt++;
		while(ins[u]){
     
			int tmp = s.top();
			s.pop();
			ins[tmp] = false;
			col[tmp] = cnt;
			colnum[cnt]++;
		}
	}
	return ;
}
void init()
{
     
	t = 0;
	cnt = 0;
	while(!s.empty()) s.pop();
	for(int i = 1;i <= n;++i)
	{
     
		ins[i] = false;
		DFN[i] = LOW[i] = col[i] = colnum[i] = 0;
		G[i].clear();
	}
}
int main(int argc, char const *argv[])
{
     
	int T;
	int kase = 0;
	cin >> T;
	while(T--)
	{
     
		cin >> n >> m;
		memset(in,0,sizeof(in));
		memset(out,0,sizeof(out));
		ll ans = (ll)n * (n-1) - m;
		init();
		for(int i = 1;i <= m;++i)
		{
     
			int x,y;
			cin >> x >> y;
			G[x].push_back(y);
		}
		for(int i = 1;i <= n;++i)
		{
     
			if(DFN[i] == 0) tarjan(i);
		}

		cout << "Case " << ++kase << ": ";
		if(cnt == 1){
     
			cout << -1 << endl;
			continue;
		}
		for(int i = 1;i <= n;++i)
		{
     
			int u = i;
			for(int j = 0;j < G[i].size();++j)
			{
     
				int v = G[i][j];
				if(col[u] != col[v]){
     
					out[col[u]]++;
					in[col[v]]++;
				}
			}
		}
		int minn = INF;
		for(int i = 1;i <= cnt;++i){
     
			if(out[i] == 0 || in[i] == 0){
     
				minn = min(minn,colnum[i]);
			}
		}
		ans -= (ll)(minn) * (n - minn);
		cout << ans << endl;
	}
	return 0;
}

你可能感兴趣的:(Tarjan,Tarjan)