敷設レンガの問題(パーフェクト) - 爆発の検索プラグDP &&

問題の意味

の$ n \倍メートルの$グリッドを考えると、各グリッドは黒または白染色しました。今$ 1 \回2 $レンガブロックの間に必要と重ならず、グリッドを網羅使用し、すべての白の格子をカバーしていますが、黒い四角のいずれかをカバーしていません。どのように多くの方法の合計をカバーしようとしています。結果は、$ M $の残りを取ります。($ 1 \当量のn \の当量15、1 \当量のM \の当量15 $)

分析

爆発の検索、それぞれが1を返すように解決策を見つけ、上から下へ、左から右へ、左上から始まります。

#include <ビット/ STDC ++ H>
 使用して 名前空間STDを、

typedefの長い 長いLL。
const  int型のmod = 1000000007 ; 

INTのN、M。
CONSTの INT MAXN = 15 + 5 ブール色[MAXN] [MAXN]。     // 偽の为の白、真の为黑
ブール[MAXN] [MAXN]使用。

INT REC(int型 I、INT J)
{ 
    場合(jは== mの)   戻り REC(I + 10);     // 进入下一行
    の場合(I == N-)   のリターンを 1。 ;     // すべてのスペースをカバーしている
    のIF(中古[I] [J]の色は|| [I] [J])   を返す REC(I、J +を1。);      // (私には必要ありません。 、j)はレンガ上に配置される

    // 放電方式の二種類試みる
    INT RES = 0 ; 
    中古[I] [J]は、 = trueに; 

    // 横放電
    IF(J + 1 <M &&中古[I]、[J +!1。 ] && !色[I]、[Jの+ 1 ])
    { 
        [Jの中古[I] + 。1 ] = trueに
        RES + = REC(I、J)。
         使用[I]、[J +1 ] = 
    } 
    // 竖着放
    場合(I + 1 <N &&使用[I +!1 ] [J] &&色[I +!1 ] [J])
    { 
        使用[I + 1 ] [j]は= 
        RES + = REC(I、J + 1 )。
        使用[I + 1 ] [j]は= 
    } 

    [I] [j]が使用 = 返すのres%のmod。
} 

int型のmain()
{ 
       // INIT色    
        scanf関数(" %d個の%のD "、&​​N、&M)。
        printf(" %dの、"、REC(00 )); 
    } 
}

この方法の時間計算量は$ O($ NM \ CDOT 2 ^ {NM})$、タイムアウトです。あなたは、メモリの検索を使用することはできません。

 

しかし、慎重な検討が実際のパラメータは、この多くの可能なを持っていないことがわかります。

各列の格子トップの種類だけ不確実性は、まだ$ M $の合計クエリではなかったです。これは、$ M $格子ステートメモリ検索コードによって行うことができる、複雑さが$ $ O(2 ^ {M} nmでの\ CDOT)です。

#include <ビット/ STDC ++ H>
 使用して 名前空間STDを、

typedefの長い 長いLL。
const  int型のmod = 1000000007 ; 

INTのN、M。
CONSTの INT MAXN = 15 + 5 const  int型 M = 十億七ブール色[MAXN] [MAXN]。     // 偽の为の白、真の为黑

int型 DP [ 2 ] [ 1 << MAXN]; 

ボイド解く()
{ 
    int型 * CRT = DP [ 0 ]、* NXT = DP [ 1]; 
    CRT [ 0 ] = 1 ;
    以下のためにint型 I = N- 1、I> = 0 ; i-- のためのINT J = M- 1 ; J> = 0 ; j-- 
        { 
           ためintです使用= 0 ; <使用(1 << M); ++使用
           { 
               場合((使用>> J&1)|| 色[I] [J])
                    NXTが[使用] = CRT [使用&〜(1 << J)]。   // 不需要在(i、j)を放置砖块
                他に
               { 
                   // 尝试2种放法
                   int型のres = 0 ;
                   もし(J + 1!<M &&((使用>>(J + 1))&1!)&&色[I] [J + 1 ])   // 横着放 
                        使用RES + = CRT [| 1 <<(j + 1 ))]。
                   もし(私は+ 1!<N &&色[I + 1 ] [J])
                        RES使用+ = CRT [| 1 << J)]。         // 竖着放 
                   NXT [使用] =のRESの%M。 
               }
           } 
            スワップ(CRT、NXT)。
        } 
    のprintf(" %d個の\ n "、CRT [ 0 ])。
} 

int型のmain()
{ 
    // INIT色 
    のscanf(" %D%dの"、&​​N、&M)。
    解決する(); 
}

 

From:「課題はコンテストのプログラミング」

おすすめ

転載: www.cnblogs.com/lfri/p/11521375.html