カットアルゴリズムのポイントで

ポイントの概念をカット

接続点とこの点場合、すべてのエッジが、この点は、カット点(カット頂点/関節点)と呼ばれ、通信にはもはや、図を削除した無向接続グラフ。

いずれかを除去した後0および3は、もはや図を通信しているので、例えば、図では、点0,3は、切断されません。0が除去され、そしてマップが2つの連結成分1、3、4に分割されている場合、3削除した場合、その後、図4は、2つの連結成分と0,1,2に分割されます。

404

どのように需要のカットポイント

使用カットポイントのためTarjanアルゴリズム(ノートは、このアルゴリズムは同様であり、またTarjanアルゴリズムと呼ばれる連結成分アルゴリズムの成分が存在し、参照ここで壁紙)。(Tarjan、フルネームロバート・タージャン、アメリカのコンピューター科学者。)

まず、ルートノードは、全体マップを介してルート・ノードから、選択された(使用DFS)。

ルートノードのため、カット点判定は非常に単純ではない - すなわち、二つ以上のサブツリー、そのカットがある場合には、サブツリーの数を算出します。あなたは二つのサブ木がお互いに達することができないこの点を、削除する場合ので。

非ルートノードの場合、ポイントは裁判官に何らかのトラブルがカットされていません。我々は、2つの配列を維持するdfn[]low[]dfn[u]いくつかの頂点の最初表すUである(最初の)訪問、low[u]uは、バック最も早い時点までさかのぼることができる非親子縁(背面側)によってサブツリー頂点その点を発現した(dfn最小値)dfn値(ただし、その親ノードUへの接続端を介して)。側面については(u, v)、もしlow[v]>=dfn[u]この時点で、uそのカット。

しかし、ここで問題があります:計算する方法low[u]

デフォルトでは、現在の頂点uと仮定low[u]=dfn[u]自体に最古のデートの後ろに、です。

エッジがあり(u, v)、場合v訪れない、継続DFSDFS終了、low[u]=min(low[u], low[v])

場合v(と訪れuないv父)、それが継続しないDFSと、存在しなければなりませんdfn[v]<dfn[u],low[u]=min(low[u], dfn[v])

参考博文:https://www.cnblogs.com/collectionne/p/6847240.html

コード

#include<bits/stdc++.h>
using namespace std;
const int MAXN=20000;
const int MAXM=100000+10;
int dfn[MAXN],low[MAXN];
bool cut[MAXN];
int ans;
int n,m,deep;
struct Node
{
    int to,next;
}edge[MAXM*2];
int cnt,head[MAXN];
inline int read()
{
    int tot=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        tot=(tot<<1)+(tot<<3)+c-'0';
        c=getchar();
    }
    return tot;
}
inline void add(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
inline void tarjan(int u,int father)
{
    int tot=0;
    low[u]=dfn[u]=++deep;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&u!=father)cut[u]=1;
            if(u==father)tot++;
        }
        low[u]=min(low[u],dfn[v]);
    }
    if(u==father&&tot>=2)cut[u]=1;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        add(x,y);add(y,x);
    }
    /*for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=edge[j].next)
            cout<<i<<" "<<edge[j].to<<endl;*/
    for(int i=1;i<=n;i++)
        if(!dfn[i])tarjan(i,i);
    for(int i=1;i<=n;i++)   
        ans+=cut[i];
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
        if(cut[i])printf("%d ",i);
    printf("\n");
    return 0;
}

ここではいくつかの演習があります

おすすめ

転載: www.cnblogs.com/hulean/p/11919835.html
おすすめ