互不侵犯King(bzoj 1087)

本文介绍了一道关于在N×N棋盘中放置K个国王,使其互不攻击的问题,并提供了一种使用状态压缩动态规划(状压DP)的方法来求解该问题的方案数量。文章详细阐述了解题思路及具体的实现代码。

Description

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

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

3 2

Sample Output

16
/*
  一看就是状压DP,而且状态也很好设,dp[i][j][s]表示前i行填了j个国王,第i行的状态是s的方案数。
  但是这样直接转移,状态太多,会超时,我们发现,由于不能攻击到相邻的,所以每一行的状态是不多的,可以预处理一下。 
*/
#include<cstdio>
#include<iostream>
#define M 600
#define lon long long
using namespace std;
lon dp[10][100][M];
int map[M][M],stay[M],num[M],m,n,k;
void dfs(int s,int last,int t){
    stay[++m]=s;
    num[m]=t;
    if(t>=k) return;
    for(int i=last+2;i<=n;i++)
        dfs(s+(1<<i-1),i,t+1);
}
int main(){
    scanf("%d%d",&n,&k);
    dfs(0,-1,0);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)
            if(stay[i]&stay[j]||((stay[i]<<1)&stay[j])||((stay[i]>>1)&stay[j]))
                map[i][j]=1;
    dp[0][0][1]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=k;j++)
            for(int s1=1;s1<=m;s1++){
                if(num[s1]>j) continue;
                for(int s2=1;s2<=m;s2++)
                    if(!map[s1][s2]&&num[s1]+num[s2]<=j)
                        dp[i][j][s1]+=dp[i-1][j-num[s1]][s2];
            }
    lon ans=0;
    for(int i=1;i<=m;i++) ans+=dp[n][k][i];
    printf("%lld",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/harden/p/6492912.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值