题目地址
题目大意
给你一个图,问你最少加多少边使得这个图变成一个连通图。
解题思路
和这道题的第二问思路差不多,就不讲了 传送门
AC代码
#include <iostream>
#include <stack>
#include <vector>
#include <cstring>
using namespace std;
const int MAX_V = 20050;
int n, m;
int DFN[MAX_V], LOW[MAX_V], link[MAX_V];
int in[MAX_V], out[MAX_V];
struct edge
{
int to;
};
vector<edge> G[MAX_V];
void add_edge(int from, int to)
{
G[from].push_back((edge){to});
}
stack<int> s;
int ans = 0, number = 0;
void margan(int v)
{
s.push(v);
DFN[v] = LOW[v] = ++ans;
for (int i=0; i<G[v].size(); i++)
{
int t = G[v][i].to;
if (!DFN[t])
{
margan(t);
LOW[v] = min(LOW[v], LOW[t]);
}
else if (!link[t])
{
LOW[v] = min(LOW[v], DFN[t]);
}
}
if (DFN[v] == LOW[v])
{
++number;
int temp;
do
{
temp = s.top();
s.pop();
link[temp] = number;
}while (v!=temp);
}
}
void init()
{
for (int i=1; i<=n; i++)
{
G[i].clear();
}
while (!s.empty())
{
s.pop();
}
memset(DFN, 0, sizeof(DFN));
memset(LOW, 0, sizeof(LOW));
memset(link, 0, sizeof(link));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
number = 0;
ans = 0;
}
int main()
{
while (~scanf("%d %d", &n, &m))
{
init();
for (int i=0; i<m; i++)
{
int x, y;
scanf("%d %d", &x, &y);
add_edge(x, y);
}
for (int i=1; i<=n; i++)
{
if (!DFN[i])
{
margan(i);
}
}
for (int i=1; i<=n; i++)
{
for (int j=0; j<G[i].size(); j++)
{
int t = G[i][j].to;
if (link[i] != link[t])
{
in[link[i]]++;
out[link[t]]++;
}
}
}
int sumin = 0, sumout = 0;
for (int i=1; i<=number; i++)
{
sumin+=in[i]?0:1;
sumout+=out[i]?0:1;
}
printf("%d\n", number == 1 ? 0:max(sumin, sumout));
}
return 0;
}