状压dp

以前从未尝试过写一个知识点,emmm可能是懒得一个个写了叭。
状压dp就是将储存很耗空间的东西转成2进制(用1与0表示状态),再转成10进制储存。(其实感觉也对bfs挺适用的)
来几道题便于理解:
【T1】国王

#include<cstdio>
int n, k, len, tmp;
long long sum, sta[1028], king[1028], dp[12][1028][103];
void init() {
 int wei = (1 << n) - 1;//A
 for(int i = 0; i <= wei; i ++) {
  if(i & (i >> 1))//B
   continue;
  sta[++ len] = i;
  tmp = i;
  while(tmp) {
   king[len] += tmp % 2;
   tmp >>= 1;
  }
 }
}
int main() {
 scanf("%d %d", &n, &k);
 init();
 for(int i = 1; i <= len; i ++)
  if(king[i] <= k)
   dp[1][i][king[i]] = 1;
 for(int i = 2; i <= n; i ++) {
  for(int j = 1; j <= len; j ++) {
   for(int u = 1; u <= len; u ++) {
    if(sta[j] & sta[u])
     continue;
    if((sta[j] << 1) & sta[u])
     continue;
    if(sta[j] & (sta[u] << 1))//C
     continue;
    for(int s = 0; s <= k; s ++)
     if(king[j] + s <= k)
      dp[i][j][king[j] + s] += dp[i - 1][u][s];
   }
  }
 }
 for(int j = 1; j <= len; j ++)
  sum += dp[n][j][k];
 printf("%lld\n", sum);
 return 0;
}

先解释一波…
A:2进制表示放不放国王,则一个状态是有n位的,考虑到有0这一位,则减一。(正好为0~n-1的1【最大情况】)
B:这个地方左移和右移都没什么问题,判断一排有没有相邻的国王。
C:同B,判断上下,斜上下的国王。

【T2】玉米田
其实这题还要简单一点,只是要讲一个关于2进制的优化。

#include<cstdio>
const int mod = 1e8;
int n, m, check[14], len;
long long sta[4099], dp[14][4099], sum;
void init() {
 int wei = (1 << m) - 1;
 for(int i = 0; i <= wei; i ++) {
  if(i & (i << 1))
   continue;
  sta[++ len] = i;
 }
}
int main() {
 int o, wei;
 scanf("%d %d", &n, &m);
 init();
 for(int i = 1; i <= n; i ++) {
  //wei = 1 << m - 1; 
  for(int j = 1; j <= m; j ++) {
   scanf("%d", &o);
   //check[i] += wei * o;
   //wei >>= 1;
   check[i] = (check[i] << 1) + o;
  }
 }
 for(int i = 1; i <= len; i ++)
  if((sta[i] & check[1]) == sta[i]) 
   dp[1][i] = 1;
 for(int i = 2; i <= n; i ++) {
  for(int j = 1; j <= len; j ++) {
   for(int k = 1; k <= len; k ++) {
    if(sta[j] & sta[k])
     continue;
    if((sta[j] & check[i]) != sta[j])
     continue;
    dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
   }
  }
 }
 for(int i = 1; i <= len; i ++)
  sum = (sum + dp[n][i]) % mod;
 printf("%lld\n", sum);
 return 0;
}

当题目给出可种范围时,学状压dp之前的我的第一想法肯定是暴力将范围与我选择的情况一一对比,然而我们有‘&’这种神奇的运算符——我们发现,在‘&’之后,如果结果与原先选择的情况相等,代表可种。(只要一个不可种,即check位是0,结果也是0,则不同了)
这里给出两种预处理check数组的写法。

如果有不对的地方,请大佬们在评论区落座呀。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值