【学习笔记】- 动态规划基础:状态压缩

喵喵放了状压的视频,跟着写了个学习笔记,不过话说还在更新中诶,先发出来真的好吗

一般用于解决棋盘式问题,是基于连通性的dp

用一个集合的格式来把 dp 问题分解掉

这里用例题来讲解状压

  • 骑士/互不侵犯

    • 状态表示

      \(f_{i,j,s}\)表示前\(i\)行已经放完,已经放了\(j\)个棋子,同时最后一行的状态是\(s\)

      • 集合

        所有只摆在前\(i\)行,已经摆了\(j\)个国王,同时第 \(i\) 行摆放的状态是 \(s\) 的所有方案的集合

        此处的\(s\)是一个二进制数,其中\(0\)表示没有国王,\(1\)表示有国王

      • 属性

    • 状态计算

      对应的是一个集合划分的过程

      转移到\(f_{i,j,s}\)的条件是

      1. \(i-1\)行内部不能有两个\(1\)相邻

      2. \(i-1\)行和第\(i\)行之间也不能相互攻击到

      \(a\)表示上一行的状态,\(b\)表示这一行的状态

      唔,由此来看满足的条件也就是

      (a&b)==0(a|b)不能有两个相邻的1

      • 转移方法

        已经摆完了前排且第\(i\)排的状态是\(a\),第\(i-1\)排的状态是\(b\),已经摆完了\(j\)的国王的所有方案 可以转化为 已经摆完了前\(i-1\)排,并且第\(i-1\)排的状态是\(b\),已经摆了j-count(a)个国王(这里的count是二进制中\(i\)的个数)的所有方案

        也就是说f[i,j,b]可以从f[i-1,j-count(a),b]转移来

        复杂度虽然是指数级的,但是我们发现\(n<9\)所以可以通过此题

    • 代码

      #include<bits/stdc++.h>
      #define int long long
      using namespace std;
      const int N=12,M=1<<10,K=110;
      int n,m;
      vector<int> state,head[M];
      int id[M],cnt[M],f[N][K][M];
      bool check(int state){
          for(int i=0;i<=n;i++){
              if((state>>i&1)&&(state>>i+1&1))
                  return false;
          }
          return true;
      }
      int count(int state){
          int res=0;
          for(int i=0;i<n;i++) res+=state>>i&1;
          return res;
      }
      signed main(){
          cin>>n>>m;
          for(int i=0;i<(1<<n);i++){
              if(check(i)){
                  state.push_back(i);
                  cnt[i]=count(i);
              }
          }
          for(int i=0;i<state.size();i++){
              for(int j=0;j<state.size();j++){
                  int a=state[i],b=state[j];
                  if(((a&b)==0)&&check(a|b))
                      head[i].push_back(j);
              }
          }
          f[0][0][0]=1;
          for(int i=1;i<=n+1;i++){
              for(int j=0;j<=m;j++){
                  for(int a=0;a<state.size();a++){
                      for(int b:head[a]){
                          int c=cnt[state[a]];
                          if(j>=c){
                              f[i][j][a]+=f[i-1][j-c][b];
                          }
                      }
                  }
              }
          }
          cout<<f[n+1][m][0]<<"\n";
      }
      
posted @ 2024-02-20 16:38  Vsinger_洛天依  阅读(42)  评论(3编辑  收藏  举报