棋盘覆盖2(1X2骨牌 和 L型骨牌 混合铺满)(强行轮廓线DP)
2016-08-17 18:36
274 查看
NYOJ435【题意】用1*2或者L型的地板铺满n*m的地面一共有多少中方案
因为多了L型骨牌,轮廓线需要判断左上方的填充情况,所以轮廓线的状态要加一位,最高位表示左上方,次高位表示上方,最低位表示左方。
状态的转移也复杂些,之前是上方有空就必填,否则没机会填了,现在因为可以填充到左上方的格子,所以上方有空也可以考虑不填,但是当当前位置是每排的最后一个时上方的格子不填就没机会 填了,所以这里要做个特判。然后左上方为空是必填的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL long long int
inline int read()
{
char ch;
int ans;
ch = getchar();
if (ch == -1)
return -1;
while (ch < '0' || ch > '9')
ch = getchar();
ans = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')
{
ans = ans * 10 + ch - '0';
}
return ans;
}
LL dp[2][1 << 10];
int main()
{
int n, m;
while (~scanf("%d %d", &n, &m))
{
if (n < m)
{
int t = m;
m = n;
n = t;
}
int h = 1 << (m - 1);
int hh = 1 << (m);
memset(dp, 0, sizeof(dp));
int cur = 0;
dp[0][(hh << 1) - 1] = 1;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
cur ^= 1;
memset(dp[cur], 0, sizeof(dp[cur]));
for (int k = 0; k < (hh << 1); ++k)
{
if (i && j && !(k & hh))//左上方没填,不能不填
{
if (!(k & h))
dp[cur][(k << 1) | hh | 1] += dp[cur ^ 1][k];//缺左下角
if (!(k & 1))
{
if ((k & h) || j != m - 1)
dp[cur][(k << 1) | 3] += dp[cur ^ 1][k];//缺右上角
if (!(k & h))
dp[cur][(k << 1) | hh | 2] += dp[cur ^ 1][k];//缺右下角
}
}
if (i && j && (k & hh))//左上方填了,可以不填
{
if (!(k & 1))
{
if ((k & h) || j != m - 1)
dp[cur][((k^hh) << 1) | 3] += dp[cur ^ 1][k];//横放
}
if (!(k & h))
{
dp[cur][((k^hh) << 1) | hh | 1] += dp[cur ^ 1][k];//竖放
if (!(k & 1))
dp[cur][((k^hh) << 1) | hh | 3] += dp[cur ^ 1][k];//缺左上角
}
if ((k & h) || j != m - 1)
dp[cur][((k^hh) << 1)] += dp[cur ^ 1][k];//不放
}
if (!i && j)
{
if (!(k & 1))
dp[cur][((k&(hh - 1)) << 1) | 3] += dp[cur ^ 1][k];//横放
dp[cur][((k&(hh - 1)) << 1)] += dp[cur ^ 1][k];//不放
}
else if (i && !j)
{
if (!(k & h))
dp[cur][((k&(hh - 1)) << 1) | hh | 1] += dp[cur ^ 1][k];//竖放
if ((k&h) || j !
9943
= m - 1)
dp[cur][((k&(hh - 1)) << 1)] += dp[cur ^ 1][k];//不放
}
else if (!i && !j)
{
dp[cur][((k&(hh - 1)) << 1)] += dp[cur ^ 1][k];//不放
}
}
}
}
printf("%lld\n", dp[cur][(hh << 1) - 1]);
}
}
因为多了L型骨牌,轮廓线需要判断左上方的填充情况,所以轮廓线的状态要加一位,最高位表示左上方,次高位表示上方,最低位表示左方。
状态的转移也复杂些,之前是上方有空就必填,否则没机会填了,现在因为可以填充到左上方的格子,所以上方有空也可以考虑不填,但是当当前位置是每排的最后一个时上方的格子不填就没机会 填了,所以这里要做个特判。然后左上方为空是必填的。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define LL long long int
inline int read()
{
char ch;
int ans;
ch = getchar();
if (ch == -1)
return -1;
while (ch < '0' || ch > '9')
ch = getchar();
ans = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')
{
ans = ans * 10 + ch - '0';
}
return ans;
}
LL dp[2][1 << 10];
int main()
{
int n, m;
while (~scanf("%d %d", &n, &m))
{
if (n < m)
{
int t = m;
m = n;
n = t;
}
int h = 1 << (m - 1);
int hh = 1 << (m);
memset(dp, 0, sizeof(dp));
int cur = 0;
dp[0][(hh << 1) - 1] = 1;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
cur ^= 1;
memset(dp[cur], 0, sizeof(dp[cur]));
for (int k = 0; k < (hh << 1); ++k)
{
if (i && j && !(k & hh))//左上方没填,不能不填
{
if (!(k & h))
dp[cur][(k << 1) | hh | 1] += dp[cur ^ 1][k];//缺左下角
if (!(k & 1))
{
if ((k & h) || j != m - 1)
dp[cur][(k << 1) | 3] += dp[cur ^ 1][k];//缺右上角
if (!(k & h))
dp[cur][(k << 1) | hh | 2] += dp[cur ^ 1][k];//缺右下角
}
}
if (i && j && (k & hh))//左上方填了,可以不填
{
if (!(k & 1))
{
if ((k & h) || j != m - 1)
dp[cur][((k^hh) << 1) | 3] += dp[cur ^ 1][k];//横放
}
if (!(k & h))
{
dp[cur][((k^hh) << 1) | hh | 1] += dp[cur ^ 1][k];//竖放
if (!(k & 1))
dp[cur][((k^hh) << 1) | hh | 3] += dp[cur ^ 1][k];//缺左上角
}
if ((k & h) || j != m - 1)
dp[cur][((k^hh) << 1)] += dp[cur ^ 1][k];//不放
}
if (!i && j)
{
if (!(k & 1))
dp[cur][((k&(hh - 1)) << 1) | 3] += dp[cur ^ 1][k];//横放
dp[cur][((k&(hh - 1)) << 1)] += dp[cur ^ 1][k];//不放
}
else if (i && !j)
{
if (!(k & h))
dp[cur][((k&(hh - 1)) << 1) | hh | 1] += dp[cur ^ 1][k];//竖放
if ((k&h) || j !
9943
= m - 1)
dp[cur][((k&(hh - 1)) << 1)] += dp[cur ^ 1][k];//不放
}
else if (!i && !j)
{
dp[cur][((k&(hh - 1)) << 1)] += dp[cur ^ 1][k];//不放
}
}
}
}
printf("%lld\n", dp[cur][(hh << 1) - 1]);
}
}
相关文章推荐
- ZooKeeper web管理安装node-zk-browser
- UVALive 7454 Parentheses
- matlab 打开文件bin
- 04# 数据分析 学习笔记(一)
- 如何实现页面中点击+号多张图片缓慢展开,再次点击×缓慢收起
- 百度云测试中心_如何开展持续集成(四)|持续集成之追求极致
- Android App整体架构
- 我的C#日记2
- fitsSystemWindow作用
- bzoj 1020 计算几何
- 64位系统访问注册表SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
- JAVA中的反射机制
- Bootstrap入门基础(六)
- [Android] 彻底了解Binder机制原理和底层实现
- LR遇到问题集锦
- zzuli oj 多校训练(三)【树链剖分--树状数组---STL----二分图----二分----DP】
- Json源生解析
- javaWeb--javaBean
- Linux基础之文件查找工具:locate、find
- Misha and Palindrome Degree