[ZJOI2011救助ピカチュウ]

フェイス質問

https://www.luogu.org/problem/P4542

不滅のタイトル。

最小パスカバレッジを行います。

以下のように、それは最低限のカバレッジが各ポイントへのパスをカバーしなければならない、この質問は同じで、ある場所があります。

この質問は4を持っており、最小のパスが異なる場所をカバー

  1. あなたは訪問を繰り返すことができます(これは$ Floyed $推移閉包を解決することができます)
  2. 各パスは、原点から開始する必要があります
  3. 各点がなければならない「から」(パスにないノード)
  4. その後、少なくとも1人があり、$ 1..x $を訪問されているものと、その最初のシーケンスは、x + 1 $ $として$ X $の要素よりも大きく、

第四ブレークポイントから私たち、私たちは$を呼び出し、その最初のシーケンスは、x + 1 $ $として$ X $の要素よりも大きい場合、少なくとも1つの$ P_Iの$があり、$ 1..x $を訪問されているものとP_I $ $ X + 1 $を破ります。

もちろん、合法的なパスカバレッジのために、人のブレークシーケンスが増加しており、シーケンスの中断は、各点が発生し、一度だけ。

その後、我々は[I] [J] $ $ DIS、最小カバレッジのシーケンスを破るために、ダイレクトパスを行いブレークを表す$ jは$の$(I <jの)$、できていないアクセスを破るために来て、この時、私は$ $です$ jは$大ノードよりも、$あなたが見つけることができる$ Floyedを行います。

皆のために、我々はすべて、最初のポイントに$ 0 $から二部グラフをそのブレークの費用を支払う必要があるため、これは、輝いていません。しかし、我々は$ K $新しい$ 0 $ポイント獲得したエッジと古いを建て$ 0 $は、同じことを指します。ネットワークフローで、直接ストリーム$ 0 $点に$ K $へ。

これはまだ問題があり、すべての最初はそれぞれの原点に対応するストリップを保証するものではありません$ K $が続く正確に$ K $ストリップを、保証することはできません。

また、非常に簡単です。

開始の間にエッジがあっても存在しないので、2つの開始点が存在することができるので、$ K $は、出発点に対応する各記事です。

$ N + k個の$点の合計は、唯一の最大流量は、N- $ $、$ K $はちょうど記事、Y $ $ $上部が確実に飽和されたホール定理、n番目の$、$ K $点以下であります最大流量はの$ n $であるので、確かに、一致していません。

コード

#include <地図> 
の#include <スタック> 
の#include <キュー> 
の#include <ベクトル> 
の#include <cstdioを> 
する#include <CStringの> 
する#include <iostreamの> 
する#include <アルゴリズム>
 の#define N 500
 の#define S 0
 の#define T(2 * N + 3)
 の#defineは長い長いLL
 の#define INTレジスタRI
 の#define INF十億七
 使用 名前空間STDを、

INTのN、M、K。
INT DIS [N] [N]。

構造体グラフ{ 
  ベクトル < 整数 >W、C、であり; 
  ベクター < INT > ED [N]。
  LL DIS [N]。INTのCUR [N]。
  BOOL VIS [N]。
  ボイド add_edge(int型int型 B、int型 AW、int型AC){ 
    to.push_back(B)。w.push_back(AW)。c.push_back(AC)。ED [A] .push_back(to.size() - 1 )。
    to.push_back(A)。w.push_back(0)。c.push_back(-ac)。ED [B] .push_back(to.size() - 1 )。
  } 
  BOOL spfa(){ 
    memsetの(DIS、0x3fをはsizeof (DIS))。
    memsetの(VIS、0はsizeof (VIS))。
    キュー < 整数 > Q; 
    DIS [S] = 0 ; q.push(S); VIS [S] = 1 一方、(!q.empty()){
       int型のx = q.front()。q.pop();
      (RI i = 0 ; iが編<[X] .size(); iは++ ){
         int型、E = ED [X] [I];
        もし(DIS [乃至[E]]> DIS [X] + C [E] && W [E]){ 
          DIS [[E]に] = DIS [X] + C [E]。
          もし(!VIS [] E [へ])VIS [に[E] = 1 、q.push([E]へ)。
        }
      }
      VIS [X] = 0 
    } 
    戻り DIS [T] < INFします。
  } 
  INT DFS(int型のx、int型LIM){
     場合(X == T || LIM!)戻りLIM。
    LLの合計 = 0 ; VIS [X] = 1 (RI&I = CUR [X]; iは<ED [X] .size(); iは++ ){
       int型、E = ED [X] [I];
      もし(DIS [X] + C [E] == DIS && W [E] [E] [する] &&!VIS [] E [に対して]){
         int型、F = DFS(LIM(分、[E]に我々])); 
        W [E] - = F。W [ 1 ^ E] + = F。
        LIM - = F。和+ = F。
        もし(!LIM)のリターン合計。
      } 
    } 
    戻り値の和。
  } 
  LLのzkw(){ 
    LLのRET = 0 一方、(spfa()){ 
      memsetの(VIS、0はsizeof (VIS))。
      memset(CUR、0はsizeof (CUR))。
      RET + = DFS(S、INF)* DIS [T]。
    } 
    戻りRET。
  } 
} G。

INT {main()の
   int型、B、L。 
  のscanf("%D%D%D "、&​​N、&M、およびK); 
  memset(DIS、0x3fをはsizeof (DIS))。
  以下のために(RI i = 0 ; iが<= N; iが++)DIS [i]は[I] = 0 (RI i = 1 ; I <= M; iは++ ){ 
    scanf関数(" %D%D%D "、&​​、&B、&L)。
    DIS [A] [B] = DIS [B] [A] = 分(DIS [A] [B]、L)。
  } 
  のための(RI KK = 0 ; KK <= N; KK ++ のための(RI i = 0 ; I <= N; I ++ のための(RI J = 0 ; J <= N; J ++であれば(KK <= I || KK <= J)DIS [I] [J] =分(DIS [I]、[J]、DIS [I] [KK] + DIS [KK] [J])。
  (RI I = 1 ;私は= N + < 1 ;私は++ のための(RIのJ = I + 1 ; J <= N + 1 J ++;)もし(!I = J)G.add_edge(I、N + 1 + jを、1、DIS [I- 1 ] [J- 1 ])。
  G.add_edge(S、1、K、0 );
  (RI I = 2 ; iが<= N + 1 G.add_edge(S、I; I ++)は10 );
   2(RI I = N +;私は<= 2 *(N + 1); i)は++ G.add_edge(I、T、10 ); 
  COUT << G.zkw()<< ENDL。
}

おすすめ

転載: www.cnblogs.com/shxnb666/p/11297017.html