円卓のPOJ 2942人の騎士(ビス点連結成分)

トピックへのリンク:http://poj.org/problem?id=2942

 

:より転載https://blog.csdn.net/lyy28906540​​6/article/details/6756821

 

質問のおおよその意味:

アーサー王は、ラウンドテーブルで開催される会議を騎士満足のいく結果を作ることができ騎士団との会議の議題の間の紛争につながるしないようにするために、それぞれが会議の前に、会議に出席騎士ため、次の要件を持っている必要があります。

1、2人の騎士、直接互いに隣接する2つの位置を座っていない嫌い。

2、会議に出席するために騎士の数が議決権の問題は結果を持つことができるようにすることですこれは、奇数でなければなりません。

 

いくつかの騎士がある場合(例えば、他のすべての騎士を嫌っていた騎士のような)すべての会議に出席することができない表示され、世界平和のためのアーサー王は騎士団から彼を拒絶するように強制されます。

       今会議に騎士の与えられた数を行く準備ができてN、M、その後憎悪に与えられた(2人の騎士の間で嫌わお互いを表す)、少なくともアーサー王の騎士が正常に会うために取り外すことが何頼みますか?

 

注:1、特定の憎悪関係は双方向である所与、一方向憎悪関係が存在しません。

それは、ラウンドテーブルであるため、2、騎士の周りが出席し、それぞれは正確に2人の騎士を持っている必要があります。これは、各座席の両側に、彼らは騎士団の騎士を持つようにバインドされています。

3、騎士が唯一可能な会議、少なくとも3人の騎士があることを、満たすことができません。

 

問題解決のアイデア:

話題の非常に強力な包括的なビューは、レポートを解決する前に、私がそうでなければこの質問は物事を行うことは非常に困難である、あなたが最初に次の点に注意してことを示唆していることを言いました:

 

1の定義された補

定義2は、連結成分をビス

定義3部グラフ

図4に示すように、奇数円の定義

図5は、そのグラフは二部グラフ法であるか否かが判断される:クロス染色

6、Tarjanのアルゴリズム

それを行うために皆を容易にするために、私は上記の点の最初の6つの知識についてここで何かを言って、私が代わりに標準的な定義の次に人気の理解を、注意してください。

1、図補体

補グラフG〜Gは、さらにすべての側面に存在しないこと、その全体が欠失し図における原稿Gのエッジです。

 

図2に示すように、通信コンポーネントビス

       全く通信が二重されていない場合に簡単に説明すると、その後、GグラフGが接続されていないようなグラフGに少なくとも二つのノードを削除します。換言すれば、任意のグラフGは、二つ以上のパスが2つの接続されたノード(注:パスが直接エッジ手段に接続されていない)の間に存在する場合、次に連結成分はビス無しサブ有向グラフG、G 'を意味していますそれは、二重通信です。

 

3、図二部

       Baiduの百科事典定義されている二部グラフ、として知られている二部グラフ、二部グラフを見ては次のように見ることができ、かつ深さに理解する必要はありません。学生が主体部グラフまで行う方法がわからないときに慎重にそれを学びます。

 

図4に示すように、奇数サイクル

点の奇数ラインにリンクアップして、得られた閉ループは、奇数サイクルです。実際には、奇数番号が奇数の円環の頂点です。

 

図5に示すように、クロス染色方法は、二部グラフを決定します

       接合染色(のみ2色染色)に向かう途中で、注目横断ノードは次いで、再描画通過できるが、トラバースDFSグラフGと、無色(色0)状態として、すべてのノードを初期化します。ノードT染色のいくつかの点で横断ましょう図のその後確かではない二部グラフG、我々は、染色された別のノードに側S-> T Sを発見し、そして色sおよびtは、染料の同じ色です。 。

       ノードの二列、着色のそれぞれが存在する二部グラフは、川の両側に似ている想像すると、再び川を渡り、そのノードが同じ側にある同じ色でなければならないからです。反対側ノードが同じ色を有していると、それは図の二部グラフGを記載することはできません。

 

6、Tarjanのアルゴリズム

       私たちは主にアルゴリズムの基本原則、特にDFN低配列と配列について学習することを願って、だけでなく、深い探索木、どのような木の枝側、後方側は何であるとは何か。

ポイントを切断する工程について学ぶために求めているTarjanのアルゴリズム(私はしかし、あなたは問題のポイントカットを解決するためにTarjanのアルゴリズム以上使用していないことを示唆していることに注意していない、我々はそれがポイントをカットしようとする過程を見ないように)プロセスは、二重連結成分を求めているので、キー。

       あなたは切削加工のポイントを見つけるためのTarjanのアルゴリズムをよく理解したいなら、気持ちのポイントを見つけるために、その後の劉Rujia「アルゴリズムアートと情報コンテスト」P285ページ、およびPOJ1523は(純粋にタイトルのカットポイントを求めて)何を参照してくださいすることをお勧めします。

劉Rujiaは長いTarjanのアルゴリズムを理解することは非常に簡単です見て、道を理解しました。

 

上記の知識のサポートを使用すると、問題解決を始めることができます。

図1は、m個のGの図の憎悪の構成を使用して、次にGポイントは、2人の騎士各嫌い表す接続する2つのエッジを有しています。

図2は、構造補グラフG G〜を示す、〜2点を接続図の縁におけるGは、二つの騎士は、隣接する位置に座ることができ表します。

図3、。〜G、請求ラウンドテーブルに従って各座席Kナイトシートの両面に、次ナイトナイトに別のものを取ることができ、ある程度の点<= 1、があってもよいが結合されているが騎士を有します(K == 2度)、次に我々は、これらの度<= 1点が単離されるか、単に接続されていることを信じている、すなわち、それらは内ラウンドテーブル「環」ではないと言うことです。

 

例えば、マップは、我々は後に図補体グラフG〜Gの構成を使用し、明らか= 0~1の騎士が、単離されると通信しない;ナイト1 = 5度、彼は単純に接続され、ナイト{2,3 、4}連結成分の一組を構成し、それらは、円卓会議「リング」です。明らかに騎士と騎士51は、リングの外にある<= 1つの条件の程度は、会合に出席し合わない、アーサー王は、世界の平和を維持するために、自然にこれらの二人は騎士団を追放します。

 

4、質問は今、どのように我々は、リングの外騎士どの知っているのですか?

私たちは、どのように我々はリングで何騎士を知っていますか、疑問に入れることができますか?明らかに、リング内のすべてのノードが二重通信である、我々はTarjanにより連結成分アルゴリズムをビスかもしれません。図〜Gは、サブグラフを接続された複数のビスを作るかもしれないことに注意し、すなわち、それは、二重の二重及びTarjanアルゴリズムの連結成分の複数のセットが探し出すのグループの連結成分の集合でいる可能性があり、その結果、各連結成分は、二重セットを得るために我々はすぐにグループに対処しなければなりません。

次のコンポーネントは、グループのために二重の通信を処理しています。

 

騎士は(リング状に)通信コンポーネントビス内5、、出席されるであろうということにはならないので、もし騎士は、リングが奇数の頂点(奇数サイクル)ではない二重通信コンポーネントが、偶数環頂点は、すべての連結成分における騎士のアーサービス排出されてきました。

 

奇数サイクルでは6、その後、どのように接続されているコンポーネントの1組を判断するのですか?

まず、私たちはここに証明していない、インターネットをサーフィンすることができ、認証プロセスを知りたい、2つの定理を受け入れなければなりません。

(1)奇数の二重丸(すなわち、ビス通信コンポーネントが奇数サイクルを含んでいた)、二奇数円のコンポーネントに接続され、他の頂点での連結成分の頂点のいくつかの場合、

(2)奇数サイクルの一組を含む接続コンポーネント場合、彼は、二部グラフであってはなりません。反対に、これは必要十分条件である、また事実です。

デュアル通信コンポーネントは、それが奇数の二重丸の通信コンポーネントであるかどうかを決定する連結成分がビス二部グラフであり、それはクロスでそれを染色、図の二部グラフであるか否かを判断するだけかどうかを決定するための図であるので!

 

7、(つまり、彼らは2つの奇数円のより多くの共通点です)、その後、順番にダブルカウントを避けるために、奇数の円内のすべての騎士は、会議に出席するために許可されていることは明らかであり、かつ1回のミーティング以上に出席することができ、いくつかの騎士があるかもしれないので、我々は騎士が会議に出席し、それらをマーク(同じマークの唯一の騎士)を作成できるように許可されていると判断番号、。最後に、Tarjanのアルゴリズムの終わりには、我々がマークされているどのように多くの人々の統計を見て、その後、これらの人々の合計数を引いたときに、数はアーサー王の残りの部分で除去されます。

 コード:

#include <iostreamの> 
する#include <アルゴリズム> 
の#include <cstdioを> 
する#include <CStringの>
 に#define 0x3f3f3f3f INF
 使用して 名前空間STDを、
typedefの長い 長いLL。
const  int型 MAXN = 1010 ;
const  int型 MAXM = 2000010 ;
構造体ノード{
     int型、U、V、NXT。
} E [MAXM]。
INT H [MAXN]、色[MAXN]。
ブール工大[MAXN]、[OK] [MAXN]、フラグ[MAXN]。
int型ST [MAXN]、[MAXN] DFN、低[MAXN]、[MAXN] TP;
int型CNT、上部、TOT、NUM、SCC、N、M。 
BOOL G [MAXN] [MAXN]。

ボイド追加(INT U、INT V)
{ 
    E [CNT] .U = U、E [CNT] .V = V。
    E [CNT] .nxt = H [U]、H [U] = CNT ++ 
} 

ボイドのinit()// 初始化
{ 
    memsetを(H、 - 1はsizeof (H))。
    memset(工大、0はsizeof (インスト))。
    memset(DFN、0はsizeof (DFN))。
    memset(フラグ、0はsizeof (フラグ))。
    memsetの(グラム、0はsizeof (G))。
    CNT = TOT =人気= NUM = SCC = 0 
} 

BOOL DFS(int型のx、int型 CL)// 染色、判断是否是二分图
{ 
    色[X] = CL。
    int型 - ;!I = [X] i = hを1 ; I = E [I] .nxt)
    { 
        int型、V = E [I] .V。
        もし(OK [V]!)続けますもし(色[V] == CL)を返す もし(!色[V] &&!DFS(V、-cl))を返す ; 
    } 
    を返す 
} 

ボイド tarjan(INT U、INT PRE)
{ 
    低い[U] =のDFN [U] = ++ TOT。
    ST [トップ ++] = U; 
    工大[U] = 1 int型 pre_cnt = 0 ;
    以下のためにint型 - ;!I = [U] = I hを1 ; I = E [I] .nxt)
    { 
        int型、V = E [I] .V。
        もし(V ==事前&& pre_cntの== 0 
        { 
            pre_cnt ++ 続け; 
        } 
        もし(!DFN [V])
        { 
            tarjan(V、U)。
            低[U] = 分(低[U]、[V]低いです)。
            もし(DFN [U] <=低い[V])// 找到U是割点
            { 
                memsetの(OK、0はsizeof (OK))。
                int型のトン。
                SCC = 0 ; 
                実行{ 
                    T = ST [ - トップ]。
                    工大[T] = 0 ; 
                    [OK]を[T] =1 ; // 染色するタグ 
                    [SCC ++] = T TPを; //は、二重により通信コンポーネントを保存 
                } ながら(T =!V); 
                OK [U] = 1 ; 
                のmemset(カラー、0はsizeof (カラー)) ;
                 IF(DFS(U、!1。 ))// 二部グラフは、奇数サイクルではない、マーカーは騎士を満たすことができる
                { 
                    フラグに[U]を = 1。;
                     一方(scc-- 
                        フラグに[TP [SCC] = 1 ; 
                }
            } 
        } 
        そう であれば(工大[V])
            低[U] = 分(低[U]、DFN [V])。
    } 
} 

ボイドは、(解決)
{ 
    int型 ANS = N。
    以下のためにint型 I = 1、私は++;;私は<= N の場合(!DFN [i])と
            tarjan(I、 - 1 );
    以下のためにint型 I = 1 iは++; iが<= N であれば(フラグ[i])と
            ANS - 
    printf(" %d個の\ nを " 、ANS)。
} 

int型のmain()
{ 
    一方(のscanf(" %d個の%のD "!、&N、&M)= EOF)
    { 
        場合(!N && m)のブレーク
        その中に(); 
        int型のuを、V。
        以下のためにint型 i = 0 ; iがm <I ++の
        { 
            scanf関数(" %d個の%dを"、&​​U、およびV)。
            G [U] [V] = G [V] [U] = 1 
        } 
        のためにint型 i = 1 ; iがn = <; iは++)// 建补图
            ためINTの J = 1 ; J <= N; J ++ 場合(I = J &&!G [I] [J])
                    を追加(I、J)。
        解決する(); 
    } 
    戻り 0 
}

 

おすすめ

転載: www.cnblogs.com/xiongtao/p/11276991.html