题解【CF1551D1】 记忆化搜索
题意: 有一个m*n的桌子,和 块多米诺 每块多米诺是2*1的 ,问恰好有k块多米诺水平放置时能否放满整个桌面
做法:记忆化搜索
灵感:首先看到数据范围 n,m<=100 ,所以想到 的算法,
于是,我发现,对于一个桌面,我们要么放一行,要么放一列。
状态 dp[i][j][k]表示放满能否用恰好k个垂直放满i*j的桌面
转移 如果目前一行的格子数是2的倍数而且平行的个数足够放一行,那么如果放了后的状态可行,该状态可行,如过一列的格子数是偶数,竖直的个数足够,那么同样放一列。
边界 dp[0][0][0]=1;(不用放了)
dp[i][j][k]=1 , 直接铺满即可
dp[i][j][k]=1 , 同上
其他情况 dp[i][j][k] = 0 ( 不能由合法状态转移来的)
代码
#include<bits/stdc++.h>
#define int long long
#define rg register
#define __max(aaa,bbb,ccc) max(max(aaa,bbb),ccc)
#define __min(aaa,bbb,ccc) min(min(aaa,bbb),ccc)
using namespace std;
template <typename T> inline void read(T &x)
{
x=0;int f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x*=f;
}
template<typename T,typename ...Args>void read(T &x,Args&...args){read(x),read(args...);}
template <typename T> inline void print(T x)
{
if(x>9) print(x/10);
putchar(x%10+48);
}
int n,m,t,k;
bool f[101][101][5001],vis[101][101][5001];
inline bool can(int x,int y,int z)
{
if(vis[x][y][z])return f[x][y][z];
vis[x][y][z]=1;
if(z>(x*y)/2)return f[x][y][z]=false;
if(x==0&&y==0&&z==0)return f[0][0][0]=true;
if(z==0&&x%2==0)return f[x][y][z]=true;
if(z==x*y/2&&y%2==0)return f[x][y][z]=true;
bool ans=0;
if(x%2==0&&(x/2)<=(x*y/2)-z) ans=(ans||can(x,y-1,z));
if(y%2==0&&(y/2)<=z) ans=(ans||can(x-1,y,z-(y/2)));
if(ans)return f[x][y][z]=true;
return false;
}
signed main()
{
read(t);
for(register int _=1;_<=t;++_)
{
read(n,m,k);
if(can(n,m,k))puts("YES");
else puts("NO");
}
}
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17971018,谢谢你的阅读或转载!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步