あなたの教室の席分布のM * nの行列表現の座席を与えます。シートは、(利用できない)悪い場合、使用「#」を示し、それ以外の場合、で表されます「」。
学生は左に見ることができ、右、左上、右上次の彼の学生の4つの方向への答えが、生徒たちは彼が答えのか、後ろの正面に座って見ることができません。仕事とリターン一緒に試験を受けて、検査室が保持できるごまかすことができない学生の最大数をしてください。
学生は席に座って良好な状態でなければなりません。
例1:
#" " 。"、「#」、「#」、「」、「#」]] 出力:4 説明する:教師は許可することができます4人の、彼らは試験でカンニングすることはできませんので、座席に座っている学生が利用できます。
プロンプト
文字だけ席' 'と' #' M == seats.length N- == 席[I] .LENGTH 1。 <= M <= 8。1。 <= N - <= 8。
1. DP状の圧力
まず、次のデータが10周りの範囲とき、あなたが考えることができ、データの範囲を見て、DPはそれを考えなければならない圧力のような学んだ男......個人的な経験は、圧力DPのようではありません。
すべてのバイナリ人、そして彼の党が持っているかどうか座った位置に列挙n個の席では、1 << n個の合計例一種です。
DP [i]はi行jに対する[j]が最大の状態であり、その後、[I] DP [J] = J +最大1つの状態(DP [I-1] [K])の数(0を含みます<= K <(1 << N)&& jおよびkは、法的地位&& jおよびkは各コピーの二つの位置に対応していないが存在しています)
ゲームコードは、隣接するポイントが存在するかどうかを判断するためにビット問題、使用J&(J << 1)にゲームの参照溶液の後......比較的醜い書き込み以上80行で記述されている場合に、より強力です -
ACコード(CPP)
クラスソリューション{ INT countOne(INT X){ int型 CNT = 0 。 しばらく(X =!0)のx = X&(X - 1)、CNT ++ ; リターンCNT; } 公共: int型 maxStudents(ベクトル<ベクトル< チャー >>&席){ int型 N = seats.size()。 INT、M =席[ 0 ] .size()。 INT ST = 1 << M。 ベクトル <ベクトル< int型>> DP(nは、ベクトル< INT >(ST、0 )); 以下のために(INT iが= 0 ; I <N; I ++ ){ int型のマスク= 0 。 用(INT J = 0 ; J <Mであり、j ++ ){ マスク + =席[I] [J] == ' #'?(1 << J):0 。 } のための(INT J = 0 ; J <ST; J ++ ){ もし!((J&マスク)&&(J&(J <<))){ int型、V = countOne(J)。 もし(I == 0)DP [I] [J] = V。 他の{ のための(int型のk = 0 ; kの<ST; K ++ ){ 場合(!((K << 1!)&J)&&((K >> 1)&J)){ DP [I] [J] = MAX(DP [I]、[J]、DP [I - 1 ] [K] + V)。 } } } } } } INT ANS = 0 。 以下のために(INT iが= 0 ; I <ST; I ++ ){ ANS = MAX(DP [N - 1 ] [i]は、ANS)。 } 戻りANS。 } }。
2部グラフの最大マッチング
あまりにも長い書かれた二部グラフは大きな神が、彼女はブログの前に再び見直さというグループによって促さ何の印象を、持っていませんなし。
この問題は、エッジの最大内部組、すなわち、最大の独立したサブセットを求めることなく収容することができる候補者の最大数を求めて、二つの接続位置のそれぞれをコピーできます。
同時に、私たちは二部グラフの性質を知っています
=独立した頂点数の最大数 - マッチの最大数
この質問二部グラフの最大マッチングのために変換されます。
もう一つ注意すべきは、テンプレートハンガリーは、二つの別々のセットポイントの場合、ほとんどの試合を求めに行くと、この質問に似ていているが、ポイントに属しポイントのどのセットを指定していないということです
したがって、すべての考えられる点が2点に分かれ、サブセットに属する各ポイントは、これは最大マッチングアルゴリズムに対応する結果です。
元のコレクションについては、答えは最大マッチング/ 2でなければなりません。
ACコード(CPP)
クラスソリューション{ 静的 のconst int型 N = 64 。 ベクター < INT > G [N]。 BOOL 使用される[N]。 int型の一致[N]。 INT R、C、N。 INT ID(int型の行、INT COL){ 戻り行* C + COL。 } ボイドは、(参加int型のx、int型Y){ G [X] .push_back(Y)。 G [Y] .push_back(X)。 } BOOL findPath(INT U){ 用(INT V:G [U]){ 場合(使用[V])続けます。 [V]使用 = 真。 もし(一致[V] == - 1 || findPath(一致[V])){ 一致[V] = U。 返す 真; } } を返す 偽。 } 公共: INT maxStudents(ベクトル<ベクトル< チャー >>&席){ R = seats.size()、C =席[ 0] .size()、N = R * C。 INT合計= 0 ; 以下のために(INT iが= 0 ; I <Rを、I ++ ){ ため(INT J = 0 ; J <C; J ++ ){ 場合(座席[I] [J] == ' ' ){ 合計 ++ 。 もし(I> 0 ){ 場合(J> 0 &&席[I - 1 ] [J - 1 ] == ' '){ // 左上 参加(ID(i、j)は、ID(I - 1、J - 1 ))。 } であれば(J + 1 <C &&席[I - 1 ] [J + 1 ] == ' '){ // 右上 参加(ID(i、j)は、ID(I - 1、J + 1 )) ; } } もし(J> 0 &&席[I]、[J - 1 ] == ' '){ // 左侧 参加(ID(i、j)は、ID(I、J - 1 ))。 } } } } int型 matchNum = 0 。 memset(一致、 - 1、はsizeof 一致)。 以下のために(INT iが= 0、I <N; I ++ ){ memsetの(使用、偽、はsizeof 使用されます)。 もし(findPath(I))++ matchNum。 } 戻り値の合計- matchNum / 2 。 } }。