sgu 223

/*
状态压缩dp


每一行的可行状态进行压缩 , n=3时 s = {000, 001, 010, 100, 101}
d[row][si][p] 表示 第row行状态为si,前row-1行已放置且不冲突,总共放了p个棋子的方案数
初始状态 d[0][0][0] = 1, others = 0;
递推公式 d[row][s[i]][p + c[i]] = sigma(d[row-1][s[j]][p])
最终解 sigma(d[n][i][k])

小优化: 将上下两行相容的状态存储起来,不用在每次dp时重复判断

 */

#include <stdio.h>

#define SIZE 146

int n, k;

int sc = 0;                      //状态总数  
int s[SIZE], c[SIZE];            //每行的可能状态s,每个状态的棋子(1)个数
long long d[12][SIZE][200];

int r[2][690];                   //上下两行可相容的状态,特许情况(0,0)
int rs = 0;                      //相容状态总数

// n*n棋盘最多放置棋子数,  写出程序后 根据结果手动添加的
int bounds[] = {0, 2, 2, 5, 5, 10, 10, 17, 17, 26, 26 };

//判断状态是否相容
int check(int si, int sj) {
  if ((si&sj) != 0) return 0;
  if (((si<<1)&sj) != 0) return 0;
  if (((sj<<1)&si) != 0) return 0;
  if (((si>>1)&sj) != 0) return 0;
  if (((sj>>1)&si) != 0) return 0;

  return 1;
}

//搜索出所有可行状态
void dfs(int si, int ci, int len) {
  if (len == n) {
    s[sc] = si;
    c[sc] = ci;
    ++sc;
  }
  else{
    dfs(si<<1, ci, len+1);
    if ((si&1) == 0) {
      dfs((si<<1) | 1, ci + 1, len + 1);
    }    
  }
}


int main() {
  scanf("%d%d", &n, &k);
  
  if (k >= bounds[n]) {
    printf("0\n");
    return 0;
  }

  if (k == 0) {
    printf("1\n");
    return 0;
  }

  dfs(0, 0, 0);
  d[0][0][0] = 1;
  
  // 初始化相容状态
  int i, j;
  for ( i=0; i<sc; ++i) {
    for ( j=i; j<sc; ++j) {
      if (check(s[i], s[j])) {
	r[0][rs] = i;
	r[1][rs] = j;
	++rs;
      }
    }
  }
  
  //dp求解
  int row = 1;
  while (row <= n) {
    for (i=0; i<rs; ++i) {
      for (j=0; j<=k; ++j) {
	int r1 = r[0][i];
	int r2 = r[1][i];
	d[row][r1][j+c[r1]] += d[row-1][r2][j];
	if (r1 != r2) {
	  d[row][r2][j+c[r2]] += d[row-1][r1][j];
	}
      }
    }
    ++row;
  }
  
  long long ans = 0;
  for (i=0; i<sc; ++i) {
    ans += d[n][i][k];
  }
  printf("%lld\n", ans);
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值