状压dp
Posted myrtle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了状压dp相关的知识,希望对你有一定的参考价值。
因为有道ac自动机+状压dp的题,故开此坑。
状压dp:状态压缩dp(元素数量通常不超过20),借助位运算将状态压缩。
空间复杂度:O(n*n)
上一行的状态为now,下一行的状态为prev,通过枚举上一行所有状态,来更新当前行、当前状态的最优解。
给定n*m矩阵,行列都不超过20,有些格子可选有些不可选,需选出最多格子使得格子之间不相邻(无公共边)
#include <iostream> #include <string.h> using namespace std; const int MAX_N=20; const int MAX_M=20; int state[MAX_N+1]; int dp[MAX_N+1][ 1 <<MAX_M]; bool not_intersect(int now,int prev) return (now&prev)==0; bool fit(int now,int flag) return(now|flag)==flag; bool ok(int x) return(x&(x/2))==0; int count(int now) int s=0; while(now) s+=(now&1); now>>=1; return s; int main() int n,m; cin>>n>>m; for(int i=1;i<=n;i++) for(int j=0;j<m;j++) int flag; cin>>flag; state[i]|=(1<<j)*flag; for(int i=1;i<=n;i++) for(int j=0;j<(1<<m);j++) if(!ok(j)||!fit(j,state[i])) continue; int cnt=count(j); for(int k=0;k<(1<<m);k++) if(ok(k)&&fit(k,state[i-1])&¬_intersect(j,k)) dp[i][j]=max(dp[i][j],dp[i-1][k]+cnt); int ans=0; for(int i=0;i<(1<<m);i++) ans=max(ans,dp[n][i]); cout<<ans<<endl; return 0;
长度不超过16的字符串S,如果一个子序列是回文串,即可以移除它,求最少经过多少步能移除整个串。
序列回文?1:min(子集a次数,a的互补子集b次数),时间复杂度O(3n+n*2n)
枚举子集代码
for (int t = 1; t < (1 << n); t++) // 枚举当前状态 dp[t] = IsPalindrome(t) ? 1 : inf; // 判断当前状态是否是回文,如果是回文则步骤数为 1 for(int i = t; i; i = (i - 1) & t) // 枚举 t 的所有子集 dp[t] = min(dp[t], dp[i] + dp[t ^ i]); // 更新当前状态的解的最小值 printf("%d\n", dp[(1 << n) - 1]); // 输出最终答案
...
以上是关于状压dp的主要内容,如果未能解决你的问题,请参考以下文章