UVALive - 4287 - Proving Equivalences(强连通分量)

时间:2023-02-05 22:32:12
UVALive - 4287 - Proving Equivalences(强连通分量)
Problem   UVALive - 4287 - Proving Equivalences

Time Limit: 3000 mSec

UVALive - 4287 - Proving Equivalences(强连通分量) Problem Description

UVALive - 4287 - Proving Equivalences(强连通分量)

Input

UVALive - 4287 - Proving Equivalences(强连通分量)

UVALive - 4287 - Proving Equivalences(强连通分量)Output

UVALive - 4287 - Proving Equivalences(强连通分量)

UVALive - 4287 - Proving Equivalences(强连通分量)Sample Input

2 4 0 3 2 1 2 1 3

UVALive - 4287 - Proving Equivalences(强连通分量) Sample Output

4

2

题解:题意就是给出一个有向图,问最少添加几条有向边能够使得整张图强连通,Tarjan缩点是比较容易想到的,之后怎么办,要用到一个结论:如果图中有a个入度为零的点,b个出度为零的点,那么max(a, b)就是答案,这个东西不太容易严格证明(在一份ppt上看到说证明难,略。。。),但是形式上想一想还是挺对的。此外mark两个结论,这两个是很容易严格证明的:

  1、DAG中唯一出度为0的点一定可以由任意点出发到达。(证明:由于无环,因此所有点都要终止在出度为0的点)

  2、DAG中所有入度不为0的点一定可以由某个入度为0的点出发到达。(证明:由于无环,入度不为零的点逆着走一定终止在入度为0的点)

 #include <bits/stdc++.h>

 using namespace std;

 #define REP(i, n) for (int i = 1; i <= (n); i++)
#define sqr(x) ((x) * (x)) const int maxn = + ;
const int maxm = + ;
const int maxs = + ; typedef long long LL;
typedef pair<int, int> pii;
typedef pair<double, double> pdd; const LL unit = 1LL;
const int INF = 0x3f3f3f3f;
const LL mod = ;
const double eps = 1e-;
const double inf = 1e15;
const double pi = acos(-1.0); int n, m;
vector<int> G[maxn];
int dfs_clock, scc_cnt;
int pre[maxn], sccno[maxn];
stack<int> S; int dfs(int u)
{
S.push(u);
int lowu = pre[u] = ++dfs_clock;
for (auto v : G[u])
{
if (!pre[v])
{
int lowv = dfs(v);
lowu = min(lowu, lowv);
}
else if (!sccno[v])
{
lowu = min(lowu, pre[v]);
}
}
if (lowu == pre[u])
{
scc_cnt++;
for (;;)
{
int t = S.top();
S.pop();
sccno[t] = scc_cnt;
if (t == u)
break;
}
}
return lowu;
} void find_scc()
{
dfs_clock = scc_cnt = ;
memset(pre, , sizeof(pre));
memset(sccno, , sizeof(sccno));
for (int i = ; i < n; i++)
{
if (!pre[i])
{
dfs(i);
}
}
} int out[maxn], in[maxn]; int main()
{
ios::sync_with_stdio(false);
cin.tie();
//freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
int T;
cin >> T;
while (T--)
{
memset(out, , sizeof(out));
memset(in, , sizeof(in));
cin >> n >> m;
for (int i = ; i < n; i++)
{
G[i].clear();
}
int u, v;
for (int i = ; i < m; i++)
{
cin >> u >> v;
u--, v--;
G[u].push_back(v);
}
find_scc();
for (int u = ; u < n; u++)
{
for (auto v : G[u])
{
if (sccno[v] != sccno[u])
{
out[sccno[u]]++;
in[sccno[v]]++;
}
}
}
int a = , b = ;
for (int i = ; i <= scc_cnt; i++)
{
if (!out[i])
a++;
if (!in[i])
b++;
}
int ans = max(a, b);
if (scc_cnt == )
ans = ;
cout << ans << endl;
}
return ;
}