成形圧力DP(超詳細な!!!)

まず、定義

概要

私たちは何と呼ばれる圧縮動的なプログラミング状態、圧力DP形使用して、コンピュータのバイナリ状態の性質を記述するためにどちらかのDPの道を。

多くの問題は、同時に、チェッカーボードのような圧力に適用された圧力のような、非常に多くの場合、BFSDP一緒に。

DP状圧力が実際にビットのみ1または0の各グリッドの状態のように見え、その検索機能を保存するバイナリ状態に圧縮され、別のある非常に一般的な動的プログラミング

たとえば:n個の* nの農場規模があり、我々は、ラインの特定の状態を記述するために、今、どこかの農場ことができます。

設けられたn = 9。

進数100 011 011(9)があり、各ビットはファームが占有されているか否かを表し、0は役に立たない、1で表され、そのような状態は、我々は、出てきたであろう。以下の表を

だから我々は、2 ^(N + 1)の最大値を必要とする- 1進数のような(バイナリ形式は、n-1)で、今は状態の表現を持っていますが、私の心は不安を感じるだろう:上記進小数の数を表し、 、DP複雑アップその偉大ではない、状態の全てを列挙?はい、実際には、圧力のようなものであるアルゴリズムは非常に暴力的である彼は、それぞれの状態を通過する必要があるので、例数は2 ^ nと表示されます、が、これは、この方法が機能しないことを意味するものではありません:いくつかのトピックが質問の意味に従うことができます、プログラム行の合計数を大幅それによって列挙を低減する低減させ、不正スキームを除外

より良好な成形圧力DP、動作に関連する知識の最初の導入ビットを理解します。

  1. 「&」記号、X&Yは、それがバイナリAND演算における2つの小数と、その10進値を返す(両方とも1 0、1)となります。(実施例3)=(10)(11)&2(10)2。
  2. 「|」記号は、X | Y、バイナリOR演算における2進数(両方とも0が0で他方が1である)、その小数の値を返すであろう。実施例3(11)| 2(10 )= 3(11)。
  3. 「^」記号、X ^ Y、バイナリ排他的論理和演算における2進数になり、その10進値を返す(異なる0、1です)。実施例3(11)、2(10)= 1(01)。
  4. '〜'記号、〜のx、ビット単位。例えば101 = 010、。
  5. 「<<」記号、左シフト演算、<< X 2、Xはゼロで埋めバイナリ2つの右端、2×<< 4倍xの等価の各ビットの左側に移動します。「>>」の記号、右シフト演算、>> 1 X X / 2に対応し、右端のバイナリを削除するX

1. x iはdirが1ビットに等しくない二進数字の分析。(最下位ビット)

方法:(((1 <<(I-1))&X)> 0)は、i-1ビット左シフト、i番目のビットで製造のみ等価が1で、他のビットがバイナリである場合は0番号。そしてXは、その後の動作は、> 0の結果ならば、i番目のビットの指示に従ってxはない、それ以外の場合はゼロで、1です。

2.バイナリ桁X iビットは1ディレクトリに変更しました。

方法:X = X |(1 <<(I-1))と同様の方法を実証しました。

3.バイナリ桁X iビットが0ディレクトリに変更します。

方法:X = X&〜(1 <<(I-1))

前記第1のバイナリ1の右端の桁が除去されます。

方法:X = X・(X-1)

第二に、典型的な例

実施例[1] ナイト(P1896 [SCOI2005非侵略)

タイトル説明

隣接する8つのグリッドを攻撃することができるキング、第ボードK(0 <= K <N Nを×)上に配置されたN×N(1 <= N <= 10)においては、それらはプログラムの総数のそれぞれを攻撃することができないことが判明。 。

入力形式

输入有多组方案,每组数据只有一行,包含两个整数 n 和 k。

输出格式

每组数据一行为方案总数,若不能够放置则输出 0。

输入样例

3 2

4 4

样例输出

16

79


实际状压dp顾名思义,就是采用位运算,来记录更多的必须记录的状态来做dp有了比较深的dp功底后只要对位运算有了解就可以解决问题。。。

考虑到每行每列之间都有互相的约束关系。因此,我们可以用行和列作为另一个状态的部分。用一个新的方法表示行和列的状态:数字。考虑任何一个十进制数都可以转化成一个二进制数,而一行的状态就可以表示成这样——例如:1010(2)

就表示:这一行的第一个格子没有国王,第二个格子放了国王,第三个格子没有放国王,第四个格子放了国王。而这个二进制下的数就可以转化成十进制: 10(10)

于是,我们的三个状态就有了:第几行(用i表示)、此行放什么状态(用j表示)、包括这一行已经使用了的国王数(用s表示)。

考虑状态转移方程。我们预先处理出每一个状态(s[x])其中包含二进制下1的个数,及此状态下这一行放的国王个数(num[x]),于是就有:

f[i][j][s]=sum(f[i−1][k][s−num[j]]),f[i][j][s]就表示在只考虑前i行时,在前i行(包括第i行)有且仅有s个国王,且第i行国王的情况是编号为j的状态时情况的总数。而k就代表第i-1行的国王情况的状态编号

 

【例题2】牧场的安排(P1879 [USACO06NOV]玉米田Corn Fields)

Farmer John 新买了一块长方形的牧场,这块牧场被划分成 M列 N 行  (1≤M≤12;1≤N≤12),每一格都是一块正方形的土地。FJ 打算在牧场上的某几格土地里种上美味的草,供他的奶牛们享用。遗憾的是,有些土地相当的贫瘠,不能用来放牧。并且,奶牛们喜欢独占一块草地,于是 FJ 不会选择两块相邻的土地,即:没有哪两块草地有公共边。当然,FJ 还没有决定在哪些土地上种草。 作为一个好奇的农场主,FJ 想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择。当然,把新的牧场荒废,不在任何土地上种草,也算一种方案。请你帮 FJ 算一下这个总方案数。

输入格式

第 1行:两个正整数 M 和 N,用空格隔开; 第 2到 M+1行:每行包含 N 个用空格隔开的整数,描述了每块土地的状态。输入的第 i+1行描述了第 i行的土地。所有整数均为 0 或 1,1 表示这块土地足够肥沃,0 则表示这块地上不适合种草。

输出格式

第 1 行:输出一个整数,即牧场分配总方案数除以 10^8的余数。

样例输入

2 3

1 1 1

0 1 0

样例输出

9


 题目大意

给N*M的棋盘,每个格子不是0就是1,1代表可以种草,否则不能。相邻两个格子不能同时种草,求种草的方案总数。

思路

状态压缩类动态规划,状压dp一般会有明显的数据范围特征,即n,m一般都在20以内。可将每一排的N个看成一个N位二进制,先预处理出每一行可以运行的状态,这样可以去掉很多无效状态(如110),然后DP处理,枚举当前有效状态和上一行有效状态的关系。

f[i][j] 表示第i行在状态j的时候的方案数,其中j我们用一个二进制数来表示。

转移的时候只要判断与当前行和上一行是否冲突即可,如果不冲突,分f[i][j]=∑f[i−1][k]其中k为不冲突的状态。Ans=∑1≤i≤numf[n][i] 就是最后的答案(num为状态总数)。

初始条件:f[1][i]=1 (1<=i<=a[1].num).

 

 

 

おすすめ

転載: www.cnblogs.com/ljy-endl/p/11627018.html