NYOJ_515_完全覆盖_剖析大神的代码

大神的解题报告:http://hi.baidu.com/newmyl/item/afc7cb0ef6ef5b7dbee97e07

1、当高度(h)和宽度(w)为奇数时:

area=h*w;

骨牌面积:2

h*w / 2!=0  -> 不能用骨牌覆盖

2、记f[i][s1]为第i-1行全满且第i行状态为s1时的种数,f[i-1][s2]为第i-2行全满且第i-1行状态为s2时的种数,则骨牌的覆盖方案数会等于f[h][w<<1-1](第h行全满状态):

结论:第i行的放置方案数,取决于第i-1行的放置方案数

对于每一个位置,3种放置方案:

 1. 竖直放置

 2. 水平放置

 3. 不放置

d为当前列号 ,初始化d, s1, s2都为0;对应以上三种放置方法,s1, s2的调整为:

1. d = d + 1, s1 << 1 | 1, s2 << 1;

2. d = d + 2, s1 << 2 | 3, s2 << 2 | 3;

3. d = d + 1, s1 << 1,   s2 << 1 | 1;

先就第一种情况解释一下,另外的两种情况可以类推

S1<<1|1即为把s1的二进制表示后面加上一个1,对就于本题来说就是(d+1)列上放

置,s2<<1即为把s2的二进制表示后面加上一个0,对于本题来说就是(d+1)列上不放置。

但为什么s1、s2会如此变化呢?s1对应于本行的状态,s2对应于上一行的状态,能竖直放置意味着上一行的(d+1)列是空着的,因此此时上一行的状态为s2<<1,同时竖置放置了之后,则本行(d+1)行放置了东西,状态于是变为s1<<1|1;

3、初始时的f值,可以假设第0行全满,第一行只有两种放法:

 1. 水平放置 d = d + 2, s << 2 | 3;
 2. 不放置   d = d + 1, s << 1;

# include <stdio.h>
# include <string.h>
long long a[2][3000];
int t,n,m;
void dfs(int d,int mm) //d列号 
{
if(d==m) 
{
   a[0][mm]++;//使用了滚动数组,当然是a[0]咯
   return;
}
if(d+1<=m)
   dfs(d+1,mm<<1);
if(d+2<=m)
   dfs(d+2,mm<<2|3);
}
void DFS(int d,int mm,int nn)//mm对应于上一行状态,nn对应于下一行状态
{
if(d==m)
{
   a[t][nn]+=a[(t+1)%2][mm];
   return;
}
if(d+1<=m) //判断防越界
{
   DFS(d+1,mm<<1,nn<<1|1); //第一种放置
   DFS(d+1,mm<<1|1,nn<<1); //第三种放置
}
if(d+2<=m) 
   DFS(d+2,mm<<2|3,nn<<2|3); //第二种放置
} 
int main()
{
int i;
while(scanf("%d%d",&n,&m)&&n&&m)
{
   if((n*m)%2)
   {
    printf("0\n");
    continue;
   }
   if(n>m) //当输入的 w > h 时,对调,因为横向的运算是指数级的, 而列向的是线性的.
    n^=m,m^=n,n^=m; //相当于swap(n,m)
   memset(a,0,sizeof(a));
   dfs(0,0);  //初始化第一行
   for(i=2;i<=n;i++)
   {
    t=(i+1)%2;
    DFS(0,0,0);
    memset(a[(t+1)%2],0,sizeof(a[0]));
   }
   printf("%I64d\n",a[(n+1)%2][(1<<m)-1]); //过不了就用cout
} return 0; }

 

转载于:https://www.cnblogs.com/A-way/archive/2013/05/07/3064099.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值