1017 [SCOI2005]互不侵犯KING 状压DP板子

 链接:https://ac.nowcoder.com/acm/contest/25022/1017
来源:牛客网

题目描述

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

输入描述:

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

输出描述:

方案数。
示例1

输入

复制
3 2

输出

复制
16

 

分析

dp[i][j][a] 表示当前是i层,总共放了j个子,第i层状态是 k

状态转移:num[x] 是x状态有多少个棋子,b是上一层状态。

dp[i][j][a] += dp[i-1][j-num[a]][b] 

当a >> 1 & b  ||  a << 1 & b || a & b || a & a<< 1 是不合法的可以continue,也可以直接预处理掉减小时空复杂度。

可以加一个n + 1 层,答案就是n + 1层,放了k个子,状态是0(没有放子)的总方案数。

ps:变量名写错了,改了好久bug,以后用多少变量写多少变量名不然容易搞混,再不济写得不一样一点。

//-------------------------代码----------------------------

//#define int ll
const int N = 9;
int n,m,k;

ll dp[11][90][1<<N];
int num[1<<N];
int nums[1<<N];
int st[11];
int cal(int x) {
    int num = 0;
    while(x) {
        if(x % 10 == 1) num ++ ;
        x /= 10;
    }
    return num;
}

void solve()
{
    cin>>n>>k;
    int cnt = 0;
    fo(i,0,(1<<n)-1) {
        if(i << 1 & i) continue;
        st[++cnt] = i;
        bitset<64> bt(i);
        nums[cnt] = bt.count();
    }
    fo(i,1,cnt) {
//         db(nums[i]);
    }
    dp[0][0][1] = 1;
    fo(i,1,n+1) {
        fo(j,0,k) {
            fo(p,1,cnt) {
                if(nums[p]>j)continue; 
                fo(q,1,cnt) {
                    if(st[q] << 1 & st[p] ||
                      st[q] >> 1 & st[p] ||
                      st[q] & st[p])continue;
                    dp[i][j][p] += dp[i-1][j-nums[p]][q];
//                     if(j-num[p] == 0) {
//                         dbb(i,q);
//                     }
                }
            }
        }
    }
    ll ans = 0;
    fo(p,1,cnt) {
        ans += dp[n][k][p];
    }
    cout<<ans<<endl;
}

signed main(){
    clapping();TLE;

//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

posted @ 2022-08-02 17:06  er007  阅读(16)  评论(0编辑  收藏  举报