果然我的水平只能写写以前的原题啊。。
地址:
用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; }