其他分享
首页 > 其他分享> > 【题解】P1896 [SCOI2005]互不侵犯

【题解】P1896 [SCOI2005]互不侵犯

作者:互联网

\(Description:\)

题面类似n皇后,不过摆的是国王

\(Sample\) \(Input:\)

3 2

\(Sample\) \(Output:\)

16

\(Solition:\)

设计状态,这种题我还是没有思路啊,怎么办啊啊啊啊啊?

看了看题解:

设计 \(f[i][j][k]\) 表示前 \(i\) 行,该行状态为 \(j\),前 \(i\) 行共放了 \(k\) 个国王的方案数

那么转移方程应该就是:(设 \(Z\) 是我们所有该行的状态,\(num\) 是这该状态要放几个国王

\(f[i][j][l]=(check(l,t))\sum_{t\subseteq Z} f[i-1][t][l-num[j]] (num[j]<=l<=k)\)

转移方程发现是可以满足无后效性的,这个时候确定,可以dp。

那么发现其实这个 \(check\) 可以快速求出

只要这个状态 \(l\) 和上一个状态 \(t\) 左上和当前和右上没有相同的 \(1\) 相交就可以了。

那么初始化很明显,第 \(1\) 行要用到第 \(0\) 行的状态,第 \(0\) 行除了全 \(0\) 这种状态,其他全都为 \(1\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,number,cnt,ans;
const int N=9+1,M=(1<<9)+1,K=9*9+1;
int s[M],f[N][M][K],num[M];
inline int lowbit(int x){
    return x&(-x);
}
inline bool check(int x,int y){
    if(x&y) return 0;
    if(x&(y<<1)) return 0;
    if(x&(y>>1)) return 0;
    return 1;
}
signed main(){
    scanf("%lld%lld",&n,&number);
    for(int i=0;i<(1<<n);++i){
        if(i&(i<<1)) continue;
        int tmp=i;
        s[++cnt]=i;
        while(tmp) { num[cnt]++;tmp-=lowbit(tmp);}
    }
    f[0][1][0]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=cnt;++j)
            for(int k=num[j];k<=number;++k)
                for(int l=1;l<=cnt;++l)
                    if(check(s[l],s[j]))
                        f[i][j][k]+=f[i-1][l][k-num[j]];
    for(int i=1;i<=cnt;++i)
        ans+=f[n][i][number];
    printf("%lld\n",ans);
    return 0;
}

标签:状态,int,题解,P1896,number,long,num,SCOI2005
来源: https://www.cnblogs.com/JCNL666/p/10712962.html