zoukankan      html  css  js  c++  java
  • 状态压缩DP总结

    POJ1185 炮兵部队问题:

    在平原上才能放置炮兵,每个炮兵的上下左右2格之内都不能出现别的炮兵

    可以考虑在当前行放置炮兵它的右侧和下侧绝对不会出现炮兵即可,左侧和上侧就能省去考虑

    明显的状态压缩dp题,但是题目所给的有10列,因为每行都与前两行的状态有关,那么也就是根据当前,上一行,上上行3行状态来修改

    dp[i][v][u]的状态方程

    因为这里直接3重循环会爆,但是我们很容易发现,可以预处理一些关于行的合法状态,那么状态数就少了很多,接下来考虑的时候就省去了行上的相关影响

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 const int N = 1<<11;
     7 int dp[105][100][100] , state[N];
     8 int can[100] , tot[100] , cnt;
     9 char str[15];
    10 
    11 void init_dfs(int k , int u , int v)
    12 {
    13     if(k<0){
    14         tot[cnt] = v;
    15         can[cnt++] = u;
    16         return;
    17     }
    18     init_dfs(k-3 , u|(1<<k) , v+1);
    19     init_dfs(k-1 , u , v);
    20 }
    21 
    22 int main()
    23 {
    24  //   freopen("a.in" , "r" , stdin);
    25     int n,m;
    26     while(scanf("%d%d" , &n , &m) != EOF)
    27     {
    28         for(int i=1 ; i<=n ; i++){
    29             scanf("%s" , str);
    30             state[i] = 0;
    31             for(int j=0 ; j<(int)strlen(str) ; j++){
    32                 state[i] <<= 1;
    33                 if(str[j] == 'P') state[i]+=1;
    34             }
    35            // cout<<"state: "<<state[i]<<endl;
    36         }
    37         //找到所有符合的状态,减少状态数
    38         cnt = 0;
    39         init_dfs(m-1 , 0 , 0);
    40      //   cout<<cnt<<endl;
    41 
    42         if(n==1){
    43             int maxn=0;
    44             for(int i=0 ; i<cnt ; i++)
    45                 if((state[1]&can[i]) == can[i])
    46                     maxn = max(maxn , tot[i]);
    47             printf("%d
    " , maxn);
    48             continue;
    49         }
    50 
    51         memset(dp , 0 , sizeof(dp));
    52         for(int i=0 ; i<cnt ; i++){
    53             for(int j=0 ; j<cnt ; j++){
    54                 int t1 = state[1]&can[i] , t2 = state[2]&can[j];
    55                 if(t1 == can[i] && t2 == can[j] && !(can[i]&can[j]))
    56                 {
    57                    // cout<<"test: "<<i<<" "<<j<<" "<<can[i]<<" "<<can[j]<<" tot: "<<tot[i]<<" "<<tot[j]<<endl;
    58                     dp[2][i][j] = tot[i] + tot[j];
    59                 }
    60             }
    61         }
    62         state[0] = (1<<m)-1;
    63         for(int i=3 ; i<=n ; i++){
    64             for(int u=0 ; u<cnt ; u++){
    65                 if((state[i]&can[u]) < can[u]) continue;
    66                 for(int v=0 ; v<cnt ; v++){
    67                     if((state[i-1]&can[v]) < can[v]) continue;
    68                     if((can[v]&can[u])) continue;
    69                     for(int w=0 ; w<cnt ; w++){
    70                         if((state[i-2]&can[w]) < can[w]) continue;
    71                         if((can[v]&can[w]) || (can[u]&can[w])) continue;
    72                         dp[i][v][u] = max(dp[i][v][u] , dp[i-1][w][v] + tot[u]);
    73                     }
    74                 }
    75             }
    76         }
    77         int maxn = 0;
    78         for(int i=0 ; i<cnt ; i++){
    79             for(int j=0 ; j<cnt ; j++)
    80                 maxn = max(maxn , dp[n][i][j]);
    81         }
    82         printf("%d
    " , maxn);
    83     }
    84     return 0;
    85 }
    View Code

    POJ 2411 木板拼接问题:

    在n*m的方格中,放1*2或者2*1的木板,问有多少摆放的种数

    题目会超int,答案输出用long long

    这里用dp[i][u]表示到达第 i 行时状态为 u ,且前面行的格子已经全部被木板填充完全,所能达到的方法种数

    每次对于当前行的状态只跟上一行有关,dp[i+1][u] += dp[i][v] 

    通过v可以拼出 u 的情况,我们总是在u,v上放2*1的板,或只在u 上放1*2的板,不能在v上放1*2的板,这样会与原来 v 作为当前行时在其上放1*2的情况重复

    且必须保证全部放完后,上一行v 全部填充满(v == (1<<m)-1) ,才更新数据

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 #define ll long long
     6 ll dp[15][10005];
     7 
     8 void dfs(int i , int u , int v , int full , int k , ll val)
     9 {
    10     if(k<0){
    11         if(v == full) dp[i][u] += val;
    12         return ;
    13     }
    14     if(k>=1 && !(u&(3<<(k-1)))) dfs(i , u|(3<<(k-1)) , v , full ,k-2 , val);
    15     if(!(u&(1<<k)) && !(v&(1<<k))) dfs(i , u|(1<<k) , v|(1<<k) , full , k-1 , val);
    16     if(!(v&(1<<k))) return ;
    17     dfs(i , u , v , full , k-1 , val);
    18 }
    19 
    20 int main()
    21 {
    22   //  freopen("a.in" , "r" , stdin);
    23     int n,m;
    24     while(scanf("%d%d" , &n , &m) ,n||m)
    25     {
    26         memset(dp , 0 , sizeof(dp));
    27         dfs(1 , 0 , (1<<m)-1 , (1<<m)-1 , m-1 , 1);
    28         for(int i=2 ; i<=n ; i++){
    29             for(int j=0 ; j<(1<<m) ; j++){
    30                 if(dp[i-1][j]) dfs(i , 0 , j , (1<<m)-1 , m-1 , dp[i-1][j]);
    31             }
    32         }
    33         printf("%I64d
    " , dp[n][(1<<m)-1]);
    34     }
    35     return 0;
    36 }
    View Code

    HDU2280 填充问题:

    将所给的积木装入平面上,保证最后剩余的格数能够尽可能的少

    因为积木最大也就两行,所以每次当前行只受上一行的影响

    dp[i][u]记录当前 i 行 状态 为 u 时剩余的格子的最小数目

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 using namespace std;
      5 const int INF = 0x3f3f3f3f;
      6 const int N = 1005;
      7 
      8 int dp[N][40] , state[N];
      9 char str[8];
     10 
     11 int cnt_0(int u)
     12 {
     13     int ans = 5;
     14     while(u){
     15         if(u&1) ans--;
     16         u>>=1;
     17     }
     18     return ans;
     19 }
     20 
     21 void dfs1(int i , int u , int cnt , int k) //k为当前的长度,从0开始
     22 {
     23     if(k < 0){
     24         dp[i][u] = min(dp[i][u] , cnt);
     25         return ;
     26     }
     27     if(k >= 1 && !(u&(3<<(k-1)))){
     28         int v = u|(3<<(k-1));
     29         dfs1(i , v , cnt-2 , k-2);
     30     }
     31     dfs1(i,u,cnt,k-1);
     32 }
     33 //u为当前行状态,v为上一行状态,cnt为当前行0的数量
     34 void dfs2(int i , int u , int v , int cnt , int k)
     35 {
     36     if(k < 0){
     37         dp[i][u] = min(dp[i][u] , cnt);
     38         return ;
     39     }
     40     if(k>=1){
     41         if(!(u&(3<<(k-1)))){
     42             int p = u|(3<<(k-1));
     43             dfs2(i , p , v , cnt-2 , k-2);
     44         }
     45         if(!(u&(3<<(k-1))) && !(v&(1<<(k-1)))){
     46             int p = u|(3<<(k-1));
     47             int q = v|(1<<(k-1));
     48             dfs2(i , p , q , cnt-3 , k-2);
     49         }
     50         if(!(u&(3<<(k-1))) && !(v&(1<<k))){
     51             int p = u|(3<<(k-1));
     52             int q = v|(1<<k);
     53             dfs2(i , p , q , cnt-3 , k-2);
     54         }
     55         if(!(v&(3<<(k-1))) && !(u&(1<<(k-1)))){
     56             int p = u|(1<<(k-1));
     57             int q = v|3<<(k-1);
     58             dfs2(i , p , q , cnt-3 , k-2);
     59         }
     60         if(!(v&(3<<(k-1))) && !(u&(1<<k))){
     61             int p = u|(1<<k);
     62             int q = v|(3<<(k-1));
     63             dfs2(i , p , q , cnt-3 , k-1);
     64         }
     65     }
     66     if(!(u&(1<<k)) && !(v&(1<<k))){
     67         int p = u|(1<<k);
     68         int q = v|(1<<k);
     69         dfs2(i , p , q , cnt-2 , k-1);
     70     }
     71     dfs2(i , u , v , cnt , k-1);
     72 }
     73 
     74 int main()
     75 {
     76   //  freopen("a.in" , "r" , stdin);
     77     int n , m;
     78     while(scanf("%d%d" , &n , &m) != EOF)
     79     {
     80         for(int i=1 ; i<=n ; i++){
     81             state[i] = 0;
     82             scanf("%s" , str);
     83             for(int j=0 ; j<5 ; j++){
     84                 int t = str[j]-'0';
     85                 state[i] = state[i]*2+t;
     86             }
     87         }
     88 
     89         memset(dp , 0x3f , sizeof(dp));
     90         dp[1][state[1]] = cnt_0(state[1]);
     91         dfs1(1 , state[1] , dp[1][state[1]] , 4);
     92 
     93         for(int i=2 ; i<=n ; i++){
     94             for(int p=0 ; p<32 ; p++){
     95                 if(dp[i-1][p] <INF){
     96                   //  cout<<"state : i: "<<i<<" p: "<<p<<" "<<dp[i-1][p]+cnt_0(state[i])<<endl;
     97                     dfs2(i , state[i] , p , dp[i-1][p]+cnt_0(state[i]) , 4);
     98                 }
     99             }
    100         }
    101         int minn = INF;
    102         for(int i=0 ; i<32 ; i++)
    103             minn = min(minn , dp[n][i]);
    104      //   cout<<minn<<endl;
    105         printf("%s
    " , minn<=m?"YES":"NO");
    106     }
    107     return 0;
    108 }
    View Code

     HDU 2442 方格填充

    通过所给的5种形式的木块无覆盖填充n*m的方格,问最多有多少方格被填充

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 
     7 const int N = 1<<6;
     8 int dp[105][N][N];
     9 
    10 void dfs(int i , int w , int v , int u , int val , int k)
    11 {
    12     if(k<0){
    13         dp[i][v][u] = max(dp[i][v][u] , val);
    14         return;
    15     }
    16     if(k>=2){
    17         if(!(w&(1<<(k-1))) && !(v&(7<<(k-2))) && !(u&(1<<(k-1))))
    18             dfs(i , w|(1<<(k-1)) , v|(7<<(k-2)) , u|(1<<(k-1)) , val+5 , k-3);
    19         if(!(v&(7<<(k-2))) && !(u&(1<<(k-1))))
    20             dfs(i , w , v|(7<<(k-2)) , u|(1<<(k-1)) , val+4 , k-3);
    21         if(!(v&(7<<(k-2))) && !(u&(1<<k)))
    22             dfs(i , w , v|(7<<(k-2)) , u|(1<<k) , val+4 , k-3);
    23     }
    24     if(k>=1){
    25         if(!(w&(1<<k)) && !(v&(3<<(k-1))) && !(u&(1<<k)))
    26             dfs(i , w|(1<<k) , v|(3<<(k-1)) , u|(1<<k) , val+4 , k-2);
    27         if(!(w&(3<<(k-1))) && !(v&(1<<k)) && !(u&(1<<k)))
    28             dfs(i , w|(3<<(k-1)) , v|(1<<k) , u|(1<<k) , val+4 , k-1);
    29     }
    30     dfs(i , w , v , u , val , k-1);
    31 }
    32 
    33 int main()
    34 {
    35   //  freopen("a.in" , "r" , stdin);
    36     int n,m;
    37     while(scanf("%d%d" , &n , &m) == 2)
    38     {
    39         memset(dp , -1 , sizeof(dp));
    40         dp[1][(1<<m)-1][0] = 0;
    41         for(int i=2 ; i<=n ; i++){
    42             for(int w=0 ; w<(1<<m) ; w++){
    43                 for(int v=0 ; v<(1<<m) ; v++){
    44                     if(dp[i-1][w][v]>=0) dfs(i , w , v , 0 , dp[i-1][w][v] , m-1);
    45                 }
    46             }
    47         }
    48         int ans = 0;
    49         for(int v=0 ; v<(1<<m) ; v++)
    50             for(int u=0 ; u<(1<<m) ; u++)
    51                 ans = max(ans , dp[n][v][u]);
    52         printf("%d
    " , ans);
    53     }
    54     return 0;
    55 }
    View Code
  • 相关阅读:
    正则获取HTML代码中img的src地址
    System.Diagnostics.Process 启动进程资源或调用外部的命令的使用
    按位取反运算符~
    Nhibernate Query By Criteria 条件查询
    Unit Test测试框架中的测试的执行顺序
    Jquery自定义插件之$.extend()、$.fn和$.fn.extend()
    如何采集QQ群中所有成员QQ号码
    Sql server使用Merge关键字做插入或更新操作
    c#类库和可移值类库的区别
    VS代码管理插件AnkhSvn
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4250215.html
Copyright © 2011-2022 走看看