dp--状压dp

Problem Description

互不侵犯
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

Analysis of ideas

把每一行的每一个状态用一个二进制数表示
定义dp[i][j][k]为第i行,状态为j,已经放了k个棋子的方案数

Accepted code

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,k;

int dp[10][1024][100];        //第i行状态为j,放了k个国王

vector<int> v;            //枚举可用的状态


int count(int x)        //计算x1的个数
{
    int res = 0;
    while(x)
    {
        res += x%2;
        x /= 2;
    }
    return res;
}

signed main()
{
    cin>>n>>k;
    int mx = 1<<n;                //状态最多有1<<n个
    for(int i = 0; i < mx; i++) 
    {
        if((i&(i<<1)) == 0 && (i&(i>>1)) == 0) v.push_back(i);            //左边和右边没有1就是可用的状态
    }
    dp[0][0][0] = 1;                //初始化
    for(int i = 1; i <= n; i++) 
    {
        for(int j : v)      //枚举第i行状态j
        {
            for(int l : v)      //枚举第i-1行l
            {   
                if((j&l) || (j&(l<<1)) || (j&(l>>1))) continue;        //不能互相攻击到
                for(int h = 0; h <= k; h++)            //枚举已经放置的国王个数
                {
                    dp[i][j][h+count(j)] += dp[i-1][l][h];
                }
            }
        }
    }
    int ans = 0;
    for(int i : v) 
    {
        ans += dp[n][i][k];
    }
    cout<<ans<<endl;
    return 0;
}
posted @ 2020-02-08 12:53  hezongdnf  阅读(155)  评论(0编辑  收藏  举报