首页 > 其他 > 详细

bzoj 1087(状压dp)

时间:2019-08-02 17:08:33      阅读:146      评论:0      收藏:0      [点我收藏+]

传送门

题意:

给你一个\(n*n\)的格子,如果第\(i\)个格子放入了棋子,则八联通方向都不能放置棋子,问放置\(k\)个棋子的方案数。

分析:

很明显可以进行\(dp\),又因为\(n\)非常的小,因此我们可以采用状态压缩的方法。设\(dp[i][state][k]\)为当前第\(i\)行的状态为\(state\)时,放置了\(k\)个棋子的方案数。

当前第i行的状态,显然可以由第\(i-1\)行的状态转移而来,而因为要满足八联通不能有棋子,因此在我们的状压\(state[I]\),和\(state[j]\)中,只要满足\(state[i]\&(state[i]<<1)\)\(state[j]\&(state[j]<<1)\)\(state[i]\&(state[j]<<1)\)\(state[i]\&(state[j]>>1)\)\(state[I]\&state[j]\)均大于\(0\)即可。最后有状态转移方程:\(dp[i][state[i]][bit(state[i])+k]+=dp[I-1][bit(state[j])][k]\)

总的时间复杂度为:\(\mathcal{O}(2^{2*n}*k)\)

代码:

#include <bits/stdc++.h>
#define maxn 10
using namespace std;
long long dp[maxn][1<<maxn][maxn*maxn];
int getbit(int x){
    int res=0;
    while(x){
        if(x&1) res++;
        x>>=1;
    }
    return res;
}
int main()
{
    int n,k;
    memset(dp,0,sizeof(dp));
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        int all=1<<n;
        for(int j=0;j<all;j++){
            if(j&(j<<1)) continue;
            if(i==1){
                if(getbit(j)<=k) dp[i][j][getbit(j)]++;
                continue;
            }
            for(int kk=0;kk<all;kk++){
                if(kk&(kk<<1)) continue;
                if((j&kk)||(j&(kk<<1))||(j&(kk>>1))) continue;
                for(int ll=0;ll<=k;ll++){
                    dp[i][j][getbit(j)+ll]+=dp[i-1][kk][ll];
                }
            }
        }
    }
    long long res=0;
    int all=1<<n;
    for(int i=0;i<all;i++){
        res+=dp[n][i][k];
    }
    printf("%lld\n",res);
    return 0;
}

bzoj 1087(状压dp)

原文:https://www.cnblogs.com/Chen-Jr/p/11289702.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!