【USACO06JAN】冗長経路冗長パス

同期:https://buringstraw.win/index.php/archives/46/

タイトル

F(1≤F≤5000)ベッシーと彼女の仲間で牧草地から別のに移動するには、時には彼らの厄介な恐ろしいツリーの一部を渡す必要があります。牛が道に行くことを余儀なくの疲れているので、彼らはそれぞれが互いに離れパスが牧草地の間にある少なくとも二つを持っているように、新しい道を構築したいので、彼らはより多くの選択肢を持っています。

これは、牧草地のすべてのペアの間に少なくとも1つのパスを持っています。説明は、新しい道路の最小数、道路の複数の接続端から端までの経路を計算し、全てのR(F-1≤R≤10000)双方向パス、二つの異なる牧草地を結ぶ各経路について説明します。互いから分離された二つのパスは、一方向に重ならない2つのパスを指します。しかし、2つの別個の経路上の同じ牧草地の一部が存在してもよいです。牧草地の間に同じのために、あなたは二つの異なる道路を持っていることが、あなたはまた、別の異なるパスとして、それらの間の道路を構築することができます。

入力フォーマット
1行目:スペースで区切られた二つの整数:とR&LT F.

ライン2..R + 1:各行は、いくつかのパスのエンドポイントでのフィールドで2スペースで区切られた整数が含まれています。

输出格式
行1:内蔵されなければならない新たなパスの数である単一の整数。

サンプル入力出力
入力サンプル#1:
7 7
1 2
2 3
3 4。
2. 5
4 5。
5。6。
5. 7。

出力サンプル#1:
2

考え

これは、1つのパス上のテンプレートのタイトルです。連結グラフのエッジを求めることはダブルエッジ連結グラフを追加することによってブリッジになり、我々は、辺の数を追加する必要が
最初にすべてのブリッジを削除し、残りはサイドダブルユニコムコンポーネントの一部です。二成分ユニコムの各辺は、頂点に縮小ブリッジに戻って加え、残っているものが木であろう。
エッジの数を増加させる必要がある、リーフノードの数がツリーの葉であると仮定するleaf == 1 ? 0 : (leaf + 1) / 2ここ数除い割り切れるです。
これは、テストされています!
UTOOLS1563883675341.png

UTOOLS1563883793008.png

コード

#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);
    }
}

おすすめ

転載: www.cnblogs.com/buringstraw/p/11239206.html