DP - 状压DP - SGU - 223 - Little Kings

DP - 状压DP - SGU - 223 - Little Kings

在 n×n 的棋盘上放 k 个国王,国王可攻击相邻的 8 个格子,求使它们无法互相攻击的方案总数。

输入格式
共一行,包含两个整数 n 和 k。

输出格式
共一行,表示方案总数,若不能够放置则输出0。

数据范围
1≤n≤10,
0≤k≤n2

输入样例:
3 2
输出样例:
16

分析:

本 题 与 — — 本题与—— 《蒙德里安的梦想》 相 似 , 只 是 摆 放 的 物 品 占 据 的 范 围 不 同 。 相似,只是摆放的物品占据的范围不同。

经 过 分 析 , 容 易 发 现 : 由 于 每 个 国 王 仅 占 据 相 邻 的 八 个 方 格 , 故 每 一 行 摆 放 的 方 案 仅 与 上 一 行 的 状 态 有 关 。 经过分析,容易发现:由于每个国王仅占据相邻的八个方格,故每一行摆放的方案仅与上一行的状态有关。

那 么 我 们 可 以 通 过 一 个 二 进 制 数 s 来 表 示 第 i 行 的 状 态 , 1 表 示 该 位 置 放 一 个 国 王 , 0 表 示 不 放 。 由 于 国 王 的 数 量 有 限 制 , 因 此 我 们 的 状 态 表 示 需 要 三 维 。 那么我们可以通过一个二进制数s来表示第i行的状态,1表示该位置放一个国王,0表示不放。\\由于国王的数量有限制,因此我们的状态表示需要三维。 si10

状 态 表 示 , f [ i ] [ j ] [ s ] : 已 经 摆 放 了 前 i 行 , 且 用 了 j 个 物 品 , 且 第 i 行 的 状 态 是 s 的 总 方 案 数 。 状态表示,f[i][j][s]:已经摆放了前i行,且用了j个物品,且第i行的状态是s的总方案数。 f[i][j][s]ijis

状 态 计 算 : 假 设 第 i 行 的 状 态 是 a , 第 i − 1 行 的 状 态 是 b , 若 a 能 够 由 b 转 移 而 来 , 需 要 满 足 : ① 、 第 i − 1 行 本 身 是 合 法 的 : 二 进 制 数 b 不 能 存 在 连 续 的 1 。 状态计算:\\假设第i行的状态是a,第i-1行的状态是b,若a能够由b转移而来,需要满足:\\①、第i-1行本身是合法的:二进制数b不能存在连续的1。 iai1babi1b1

② 、 状 态 a 和 状 态 b 不 能 存 在 冲 突 : Ⅰ 、 第 i 行 放 国 王 的 位 置 的 正 上 方 不 能 有 国 王 , 需 满 足 a & b = 0 。 ②、状态a和状态b不能存在冲突:\\\qquadⅠ、第i行放国王的位置的正上方不能有国王,需满足a\&b=0。 abia&b=0

Ⅱ 、 第 i 行 放 国 王 的 位 置 的 斜 上 方 不 能 有 国 王 , 需 满 足 a ∣ b 表 示 的 二 进 制 数 不 能 有 连 续 的 1 。 这 一 条 件 同 时 也 避 免 了 第 i 行 出 现 连 续 的 1 。 \qquadⅡ、第i行放国王的位置的斜上方不能有国王,需满足a|b表示的二进制数不能有连续的1。\\\qquad这一条件同时也避免了第i行出现连续的1。 iab1i1

若 满 足 以 上 两 个 条 件 , 转 移 方 程 : f [ i ] [ j ] [ a ] + = f [ i − 1 ] [ j − c o u n t ( a ) ] [ b ] , 其 中 c o u n t ( a ) 表 示 状 态 a 中 1 的 个 数 , 即 第 i 行 摆 放 国 王 的 数 量 。 \qquad若满足以上两个条件,转移方程:f[i][j][a]+=f[i-1][j-count(a)][b],\\\qquad其中count(a)表示状态a中1的个数,即第i行摆放国王的数量。 f[i][j][a]+=f[i1][jcount(a)][b]count(a)a1i

具体落实:

① 、 先 预 处 理 每 一 行 的 所 有 合 法 状 态 ( 不 能 含 有 连 续 的 1 ) , 同 时 记 录 下 这 些 状 态 当 中 1 的 个 数 ( 状 态 转 移 的 时 候 要 用 ) 。 ①、先预处理每一行的所有合法状态(不能含有连续的1),同时记录下这些状态当中1的个数(状态转移的时候要用)。 (1)1()

② 、 将 所 有 互 不 影 响 的 状 态 预 处 理 出 来 , 用 h e a d 数 组 做 一 个 映 射 。 ②、将所有互不影响的状态预处理出来,用head数组做一个映射。 head

③ 、 计 算 每 个 状 态 的 方 案 总 数 。 ③、计算每个状态的方案总数。

注意:

① 、 初 始 化 边 界 。 对 每 一 层 而 言 , 摆 放 的 国 王 数 量 为 0 时 也 是 一 种 合 法 方 案 , 因 此 国 王 数 量 j 从 0 开 始 循 环 。 ①、初始化边界。对每一层而言,摆放的国王数量为0时也是一种合法方案,因此国王数量j从0开始循环。 0j0

② 、 最 后 要 输 出 第 n 层 的 方 案 总 数 之 和 , 即 ∑ f [ n ] [ m ] [ s ] , 我 们 可 以 在 计 算 时 算 到 n + 1 层 , 最 后 输 出 f [ n + 1 ] [ m ] [ 0 ] , 这 是 等 价 的 。 因 为 状 态 为 0 可 由 前 一 层 的 所 有 合 法 状 态 转 移 而 来 , 相 当 于 在 计 算 方 案 数 的 过 程 中 就 做 了 一 遍 求 和 。 ②、最后要输出第n层的方案总数之和,即\sum f[n][m][s],\\\qquad我们可以在计算时算到n+1层,最后输出f[n+1][m][0],这是等价的。\\\qquad 因为状态为0可由前一层的所有合法状态转移而来,相当于在计算方案数的过程中就做了一遍求和。 nf[n][m][s]n+1f[n+1][m][0]0
代码:

#include<iostream>
#include<algorithm>
#include<vector>

#define ll long long

using namespace std;

const int N=12,M=1<<10,K=110;

int n,m;
ll f[N][K][M];
int cnt[M];
vector<int> state;
vector<int> head[M];

bool check(int x)
{
    for(int i=0;i<n-1;i++)
        if((x>>i)&1 && (x>>i+1)&1)
            return false;
    return true;
}

int Count(int x)
{
    int res=0;
    for(int i=0;i<n;i++) res+=(x>>i)&1;
    return res;
}

int main()
{
    cin>>n>>m;
    
    for(int i=0;i<1<<n;i++)
        if(check(i))
        {
            state.push_back(i);
            cnt[i]=Count(i);
        }
    
    int len=state.size();
    for(int i=0;i<len;i++)
        for(int j=0;j<len;j++)
        {
            int a=state[i],b=state[j];
            if((a&b)==0 && check(a|b))
                head[i].push_back(j);
        }
    
    f[0][0][0]=1;
    for(int i=1;i<=n+1;i++)
        for(int j=0;j<=m;j++)
            for(int a=0;a<len;a++)
                for(int b:head[a])
                {
                    int c=cnt[state[a]];
                    if(j>=c) f[i][j][state[a]]+=f[i-1][j-c][state[b]];
                }
            
    cout<<f[n+1][m][0]<<endl;
    
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值