广场铺砖问题(floor.pas/c/cpp)
有一个 W 行 H 列的广场,需要用 1*2小砖铺盖,小砖之间互相不能重叠,问
有多少种不同的铺法?
输入数据:
只有一行 2个整数,分别为 W 和 H,(1<=W,H<=11)
输出数据:
只有 1个整数,为所有的铺法数。
样例:
Floor.in
2 4
Floor.out
5
样例铺法如下图:
有一个 W 行 H 列的广场,需要用 1*2小砖铺盖,小砖之间互相不能重叠,问
有多少种不同的铺法?
输入数据:
只有一行 2个整数,分别为 W 和 H,(1<=W,H<=11)
输出数据:
只有 1个整数,为所有的铺法数。
样例:
Floor.in
2 4
Floor.out
5
样例铺法如下图:
感觉是SCOI2011的简化版,因为只用记录有没有插头。
这道题的范围比较小。
总方案数是2^12。.
如果用开散列会超时
如果不用散列表也会超时
所以就用普通的散列表就不会超时了。。。。。。。
注意必须用long long否则大数据要爆。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::swap;
long w;long h;
long ths = 1;
long pre = 0;
const long MaxStaus = 4100;
long cnt[2];
long long f[2][MaxStaus];
long Status[2][MaxStaus];
long tmp[MaxStaus];
long get_ID(long Sta)
{
if (tmp[Sta]>0)
return tmp[Sta];
cnt[ths] ++;
f[ths][cnt[ths]] = 0;
tmp[Sta] = cnt[ths];
Status[ths][cnt[ths]] = Sta;
return cnt[ths];
}
void clear()
{
cnt[ths] = 0;
memset(tmp,0,sizeof(tmp));
}
void dp()
{
f[ths][get_ID(0)] = 1;
for (long i=1;i<w+1;i++)
{
for (long j=1;j<h+1;j++)
{
swap(ths,pre);
clear();
for (long k=1;k<cnt[pre]+1;k++)
{
long Last = Status[pre][k];
long long val = f[pre][k];
if (j == 1)
{
if ((Last&1) == 0)
{
Last >>= 1;
}
else continue;
}
long q = h-j;
long p = q+1;
long wp = (Last>>p)&1;
long wq = (Last>>q)&1;
long Now = Last - (wq<<q) - (wp<<p);
if (wp == 1 && wq == 1)
continue;
if (wp == 0 && wq == 0)
{
f[ths][get_ID(Now|(1<<q))] += val;
f[ths][get_ID(Now|(1<<p))] += val;
}
if (wp == 0 && wq == 1)
{
f[ths][get_ID(Now)] += val;
}
if (wp == 1 && wq == 0)
{
f[ths][get_ID(Now)] += val;
}
}
}
}
std::cout << f[ths][get_ID(0)];
}
int main()
{
freopen("floor.in","r",stdin);
freopen("floor.out","w",stdout);
std::cin >> w >> h;
dp();
return 0;
}