状压DP
一.状压DP实质
1.压缩状态:当一个状态是多个(最多不超过20,因为1<<20就时1e6了,放不下了)0/1状态的量的集合时,用枚举状态压缩的方式来枚举每一层的不同状态
状态转移:判断两层的两个状态间能否转移就好
2.总结:只是用了不同的方式枚举每一层的状态,本质上还是DP思想
二.例题
1.题目1
#include<iostream> #include<cstdio> #include<iomanip> #include<cmath> #include<cstring> using namespace std; #define kuan 1<<11 #define LL long long LL f[12][kuan]; LL h, w, W; bool fit(LL last, LL now) { bool right = 1; for(LL i = 0; i < w; i++) { LL wei = 1<<i; if(!(last & wei))//上一层的wei位无 { if(!(now & wei)) { right = 0;//这一层就该有 break; } } else if(last & wei)//上一层wei有 { if(!(now & wei))//这一层可以没有 continue; else//但是有的话这一层的下一位也必须要有 { if(i == (w-1))//如果是最后一位就直接不可能了 { right = 0; break; } LL nextwei = 1<<(i+1);//下一位 if((now & nextwei) && (last & nextwei))//上一层wei也必须有,下一层的wei也必须有 { i++;//下一位就不用判断了 continue; } else { right = 0;//不满足就是错的 break; } } } } return right; } int main() { while(~scanf("%lld %lld", &h, &w) && (h || w))//输入成功 { memset(f, false, sizeof(f));//由于要求方案总数,那么得先把方案数全设为0 W = 1<<w;//压缩状态的上限状态+1 f[0][W-1] = 1;//f[i][j]表示i层为j状态时的方案数,此处是将0层的全都放满了状态赋值为1 for(int i = 1; i <= h; i++)//i表示当前层数 for(int j = 0; j < W; j++)//上一层的状态 { if(!f[i-1][j])//如果f==0就没必要判断能否转移了(剪枝) continue; for(int k = 0; k < W; k++)//这一层的状态 if(fit(j, k))//如果能转移 f[i][k] += f[i-1][j];//状态转移 } printf("%lld\n", f[h][W-1]);//输出最终层也被搞满了的样子 } return 0; }

浙公网安备 33010602011771号