飞行棋

做题时间:2021.02.03

在一个N×M(N,M10)的棋盘上,放置k(k10)种不同颜色的棋子将棋盘填满,每一种有无限个,在任意一条从左上角到右下角的路径上不得出现任意两个相同颜色的棋子。问有多少种方案数。

样例一
2 2 4
0 0
0 0
样例二
3 3 5
0 0 0
0 0 0
4 0 0
样例三
3 3 5
0 0 0
0 0 1
0 0 0

样例一
48
样例二
24
样例三
24

搜索、剪枝

#include<cstdio>
#include<iomanip>
using namespace std;
const int MOD=1e9+7;
int cnt[20];//记录当前第i个颜色出现的次数
int f[20][20];//记录当前填色的情况
int a[20][20];//记录棋盘情况
int check(int x)//查找x中有多少个1,即之前已经填了多少个颜色
{
int ans=0;
while(x){
if(x&1) ans++;
x>>=1;
}
return ans;
}
int n,m,k;
int DFS(int x,int y)
{
if(y==m+1) x++,y=1;
if(x==n+1) return 1;
int now=f[x-1][y]|f[x][y-1];//剪枝2:获取当前所用的颜色总数
int p=-1,res=0;
if(k-check(now)<n+m-x-y+1) return 0;//剪枝2:判断剩下的颜色是否大于之后的路径长度
for(int i=1;i<=k;i++){
if((now>>i-1)&1) continue;//剪枝1:如果在当前第i个颜色已经填过,则不合法
if(a[x][y]==i||a[x][y]==0){
cnt[i]++;
f[x][y]=now+(1<<i-1);//将第i个颜色标记上
if(cnt[i]!=1){
res+=DFS(x,y+1);
res%=MOD;
}
else{//剪枝3:所有第一次出现的颜色,方案数都是一样的
if(p==-1){
p=DFS(x,y+1);
res+=p;
res%=MOD;
}
else{
res+=p;
res%=MOD;
}
}
cnt[i]--;
}
}
return res;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
if(a[i][j]) cnt[a[i][j]]++;//提前标记
}
}
printf("%d\n",DFS(1,1)%MOD);
return 0;
}

本文作者:lxzy

本文链接:https://www.cnblogs.com/Unlimited-Chan/p/14370903.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   lxzy  阅读(105)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.