P1896 [SCOI2005]互不侵犯 状压dp

  

题目描述

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

注:数据有加强(2018/4/25)

输入输出格式

输入格式:

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

输出格式:

所得的方案数

输入输出样例

输入样例#1: 复制
3 2
输出样例#1: 复制
16


非常好的状压dp
注意预处理完就很好做
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define ll long long
#define pb push_back
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 0x3f3f3f3f
#define lson l,m,pos<<1
#define rson m+1,r,pos<<1|1
const int N=900;
ll dp[10][50000][500];
int cnt,king[N],state[N];
int n,K;
void init()
{
    rep(i,0,(1<<n)-1)
    if( !(i&(i<<1)) )
    {
        state[++cnt]=i;
        int temp=i;
        while(temp)
        {
            king[cnt]+=temp&1;
            temp>>=1;
        }
    }
}
int main()
{
    RII(n,K);
    init();

    rep(i,1,cnt)
    if(king[i]<=K)
    dp[1][i][king[i]]=1;

    rep(i,2,n)
    rep(j,1,cnt)
    rep(p,1,cnt)
    {
        if(state[j]&state[p])continue;
        if( (state[j]<<1)&state[p] )continue;
        if( state[j]&(state[p]<<1))continue;

        rep(s,king[j],K)
        dp[i][j][s]+=dp[i-1][p][s-king[j]];
    }
    ll ans=0;

    rep(j,1,cnt)
    ans+=dp[n][j][K];
    cout<<ans;

    return 0;
}
View Code







原文地址:https://www.cnblogs.com/bxd123/p/10850447.html