标签:inf include mes pen class 空间复杂度 max hide turn
因为有道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]); // 输出最终答案
...
标签:inf include mes pen class 空间复杂度 max hide turn
原文地址:https://www.cnblogs.com/myrtle/p/11441144.html