题目#
F (1≤F≤5000) 個の牧場のうちの 1 つから別の牧場に移動するために、ベッツィと彼女の仲間たちは時々嫌いな恐ろしい木を通らなければならないことがあります。牛たちは強制的に特定の道を歩くことにうんざりしているので、彼らはいくつかの新しい道を建設し、各牧場の間に少なくとも 2 つの分離されたパスがあるようにしたいと考えています。これにより、彼らはより多くの選択肢を持つことができます。
各牧場の間にはすでに少なくとも 1 つのパスがあります。R (F-1≤R≤10000) 本の双方向道路の説明が与えられるので、新たに建設する必要がある最小の道路の数を計算してください。パスは複数の道路が連結されてできています。2 つのパスが分離されているとは、2 つのパスが一つの道路も共有していないことを指します。ただし、分離されたパスには一部の共通する牧場がある場合もあります。同じ牧場の間には、既に 2 つの異なる道路が存在するかもしれませんが、それらの間にもう 1 つの道路を建設して、別の道路として扱うことができます。
入力形式:
1 行目:2 つの整数 F と R(F と R はスペースで区切られています)
2 行目から R+1 行目:各行には、いくつかのパスの端点である 2 つの整数がスペースで区切られています。
出力形式:
1 行目:新たに建設する必要がある道路の数を表す整数 1 つ
入出力例
入力例 #1:
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7
出力例 #1:
2
思路#
これは一本通のテンプレート問題です。橋がある連結グラフを辺連結グラフにするために、追加する必要がある辺の数を求めます。
まず、すべての橋を削除し、残りはいくつかの辺連結成分です。各辺連結成分を 1 つの頂点に縮小し、橋を追加し、最後に残るのは木になります。
葉の数を leaf とし、追加する必要のある辺の数はleaf == 1 ? 0 : (leaf + 1) / 2
となります。ここでの除算は整数除算です。
これはテスト済みです!
コード#
#include <cstdio>
#include <iostream>
#include <stack>
#include <cmath>
using std::stack;
using std::min;
const int MAXN = 40000 + 5;
namespace m1 {
struct ed {
int to, nex, frm;
} e[MAXN];
int head[MAXN];
int newp = 1;
int low[MAXN], dfn[MAXN], out[MAXN];
int tim;
int dcnt;//双連結成分の番号
int dcolor[MAXN];//双連結成分の色
bool bridge[MAXN];
void insert (int p1, int p2);
void tarjan (int p, int ed);
void dfs (int p);
}
int n, m;
int main (void) {
{
using namespace m1;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) {
int x, y;
scanf("%d%d", &x, &y);
insert(x, y);
insert(y, x);
}
tarjan(1, 0);
for (int i = 1; i <= n; ++i) {
if (!dcolor[i]) {
++dcnt;
dfs(i);
}
}
for (int i = 1; i <= m; ++i) {
if (dcolor[e[i * 2].frm] != dcolor[e[i * 2].to]) {
++out[dcolor[e[i * 2].frm]];
++out[dcolor[e[i * 2].to]];
}
}
int leaf = 0;
for (int i = 1; i <= dcnt; ++i) {
if (out[i] == 1) {
++leaf;
}
}
printf("%d\n", leaf == 1 ? 0 : (leaf + 1) / 2);
}
return 0;
}
void m1::insert (int p1, int p2) {
++newp;
e[newp].frm = p1;
e[newp].to = p2;
e[newp].nex = head[p1];
head[p1] = newp;
}
void m1::tarjan (int p, int ed) {
dfn[p] = low[p] = ++tim;
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (!dfn[y]) {
tarjan(y, i);
low[p] = min(low[p], low[y]);
if (dfn[p] < low[y]) {
bridge[i] = bridge[i ^ 1] = 1;
}
}
else if (i != (ed ^ 1)) {
low[p] = min(low[p], dfn[y]);
}
}
}
void m1::dfs (int p) {
using namespace m1;
dcolor[p] = dcnt;
for (int i = head[p]; i; i = e[i].nex) {
int y = e[i].to;
if (dcolor[y] != 0 || bridge[i] == 1) {
continue;
}
dfs(y);
}
}