【插头DP】广场铺砖

来源:互联网 发布:3个数最小公倍数算法 编辑:程序博客网 时间:2024/04/27 17:45
广场铺砖问题(floor.pas/c/cpp)
 
有一个 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;}


原创粉丝点击