codevs 2451 互不侵犯(状丫dp)

/*
好神奇好神奇...表示自己要学的还很多
注意到n<=9 不是搜索就是状丫
搜索+剪枝 70分 枚举放或者不放
这里用状丫 f[i][j][k] 表示前i行 放了j个国王 i行的状态是k的方案数
转移的话 枚举下层的状态 算出这个状态中有几个国王 然后更新
复杂度 2^n*2^n*n*K*n 最后一个n是算国王数 这个可以预处理搞出来
还有一个问题就是 互相伤害的问题
首先在同一行里 相邻的不行 不同行的就左移右移一下就好了 顺带处理好两个状态能不能互相转移
最后Σf[n][K][i] 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 520
using namespace std;
int n,K,v1[maxn],v2[maxn][maxn],cnt[maxn];
long long ans,f[10][100][maxn];
void Get_v()
{
    for(int i=0;i<(1<<n);i++)
      if((i&(i>>1))==0)
        {
          v1[i]=1;int c=0;
          for(int j=i;j;j>>=1)c+=j&1;
            cnt[i]=c;
        }
    for(int i=0;i<(1<<n);i++)if(v1[i])
      for(int j=0;j<(1<<n);j++)if(v1[j])
        if((i&j)==0&&(i&(j>>1))==0&&(j&(i>>1))==0)
          v2[i][j]=1;
}
int main()
{
    cin>>n>>K;
    Get_v();
    for(int i=0;i<(1<<n);i++)
      f[1][cnt[i]][i]=1;
    for(int i=2;i<=n;i++)
      for(int j=0;j<(1<<n);j++)if(v1[j])
        for(int k=0;k<(1<<n);k++)if(v2[j][k])
          for(int r=cnt[j];r+cnt[k]<=K;r++)
            f[i][r+cnt[k]][k]+=f[i-1][r][j];
    for(int i=0;i<(1<<n);i++)
      ans+=f[n][K][i];
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2016-08-15 21:38  一入OI深似海  阅读(300)  评论(0编辑  收藏  举报