【SSOJ 2872: 「一本通 5.4 例 1」骑士】题解
题目
在 的棋盘上放 个国王,国王可攻击相邻的 个格子,求使它们无法互相攻击的方案总数。
对于全部数据,
思路
方法一:爆搜
方法二:状压dp
每行很大,不可能开个十几维数组,怎么办?
把每行压成一个二进制!
设 表示第 行放置状态为 ,前 行共放 个棋子的方案数。
那么转移呢?
我们可以枚举上一层的情况 (也是一个二进制数)。
此时如何满足无法互相攻击呢?
(x&(x<<1)=0
和(y&(y<<1))=0
:左右不互相攻击(x&y)==0
:上下不互相攻击(x&(y<<1))==0
和(x&(y>>1))==0
:斜着不互相攻击
好了,解决了状态和转移,初始化呢?
在第一行,我们可以枚举所有可能,赋值为1。
那么统计结果呢?
同理。
我们可以枚举最后一行的所有可能,加起来,就是答案。
时间复杂度:状态+转移=
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n, m, i, j, k;
int dp[15][150][1050];
int ans, a, b;
int qiu(int x) //求这种状态有多少个棋子
{
int ans=0;
while(x) ++ans, x-=x&-x;
return ans;
}
signed main()
{
scanf("%lld%lld", &n, &k);
for(i=0; i<(1<<n); ++i) //初始化
if((m=qiu(i))<=k && !(i&(i<<1)))
dp[1][m][i]=1;
for(i=2; i<=n; ++i) //第几行
for(b=0; b<(1<<n); ++b) //这一行状态
for(a=0; a<(1<<n); ++a) //上一行状态
if(!(a&b) && !(a&(b<<1)) && !(a&(b>>1)) && !(b&(b<<1))) //不互相攻击
for(j=(m=qiu(b))+qiu(a); j<=k; ++j)
dp[i][j][b]+=dp[i-1][j-m][a]; //转移
for(i=0; i<(1<<n); ++i) ans+=dp[n][k][i]; //统计答案
printf("%lld", ans);
return 0;
}
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/15818062.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!