题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767
Consider the following exercise, found in a generic linear algebra textbook.
Input On the first line one positive number: the number of testcases, at most 100. After that per testcase:
Output Per testcase:
Sample Input 2 4 0 3 2 1 2 1 3
Sample Output 4 2 |
给一张图,问需要添加几条边,使得图变成强联通图
先求这张图的强连通分量,如果为1,则输出0(证明该图不需要加边已经是强连通的了),否则缩点。遍历原图的所有边,如果2个点在不同的强连通分量里面,建边,构成一张新图。统计新图中点的入度和出度,取入度等于0和出度等于0的最大值(因为求强连通缩点后,整张图就变成了一个无回路的有向图,要使之强连通,只需要将入度=0和出度=0的点加边即可,要保证加边后没有入度和出度为0的点,所以取两者最大值)
#pragma GCC optimize(2)
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<set>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 1e5 + 100;
const int inf = 0x3f3f3f3f;
typedef long long ll;
struct node
{
int u, v, next;
}edge[maxn];
int dfn[maxn], low[maxn], Stack[maxn], instack[maxn], belong[maxn];
int head[maxn], in[maxn], ou[maxn];
int tot, n, m, index, cnt, stop;
void init()
{
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(in, 0, sizeof(in));
memset(ou, 0, sizeof(ou));
memset(Stack, 0, sizeof(Stack));
memset(instack, 0, sizeof(instack));
memset(belong, 0, sizeof(belong));
index = tot = 0;
stop = cnt = 0;
return;
}
void addedge(int u, int v)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
return;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++index;
instack[u] = 1;
Stack[stop++] = u;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u])
{
cnt++;
int v;
do
{
v = Stack[--stop];
instack[v] = 0;
belong[v] = cnt;
} while (u != v);
}
}
int main()
{
//freopen("C://input.txt", "r", stdin);
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d%d", &n, &m);
init();
int incnt, oucnt;
incnt = oucnt = 0;
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
}
for (int i = 1; i <= n; i++)
{
if (!dfn[i])
{
tarjan(i);
}
}
if (cnt == 1)
{
printf("0\n");
continue;
}
for (int i = 1; i <= n; i++)
{
for (int j = head[i]; j != -1; j = edge[j].next)
{
int v = edge[j].v;
if (belong[v] != belong[i])
{
in[belong[v]]++;
ou[belong[i]]++;
}
}
}
for (int i = 1; i <= cnt; i++)
{
if (!in[i])
{
incnt++;
}
if (!ou[i])
{
oucnt++;
}
}
printf("%d\n", max(incnt, oucnt));
}
return 0;
}