果然我的水平只能写写以前的原题啊。。

地址:

用dp[i][j][k]表示第i行放的状态为j,前i行总共放了k个的合法方案数

那么dp[i][j][k]+=dp[i-1][p][k-val[p]](p是枚举的上一行的放的状态,val[p]表示这个状态下是放了几个)(当然先得保证j和k的方法分别合法且互相间不冲突)

那么这题就完成了。

时间复杂度O(2^2n*n^3)其实这么算算时间复杂度好像有点大,但是其实因为很多状态本身就不合法根本就不会运行,程序就过了。

但是呢,我比较懒,是直接循环的,如果要保险一点,建议先把那些合法的状态先预处理出来,会省很多时间。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef long long ll;
ll ans,dp[10][550][100];
int n,m,val[1000],bin[20];
int calc(int x)
{
  int tot=0;
  while (x) tot+=x&1?1:0,x=x>>1;
  return tot;    
} 
int main()
{
  scanf("%d%d",&n,&m);
  bin[0]=1;
  for (int i=1;i<=n;i++) bin[i]=bin[i-1]<<1;
  for (int i=0;i<bin[n];i++)
  val[i]=calc(i);
  for (int i=0;i<bin[n];i++) 
  if (!(i&(i<<1)))  dp[1][i][val[i]]=1;
  for (int i=2;i<=n;i++)
  for (int j=0;j<bin[n];j++)
  if (!(j&(j<<1))) 
  for (int k=0;k<bin[n];k++)
  if ((!(j&k))&&(!(j&(k>>1)))&&(!(j&(k<<1))))
  for (int p=0;p<=m;p++)
  if (p+val[j]<=m) 
   dp[i][j][p+val[j]]+=dp[i-1][k][p];
  for (int i=0;i<bin[n];i++) ans+=dp[n][i][m];
  printf("%lld\n",ans);
  return 0;
} 

 

posted on 2017-12-01 21:01  nhc2014  阅读(132)  评论(0编辑  收藏  举报