UVa OJ 11270

1、经典的骨牌覆盖问题,用轮廓线动态规划解决。。。看了好几个小时,终于明白了。数据有点BT,会重复,所以要用数组保存算过的值,注意memo的大小是【maxn*maxn】【maxn*maxn】的,因为最小值m<=10不意味着m,n均小于等于10,极端数据是1,100。

2、滚动数组以及异或运算的运用很巧妙。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,cur;
const int maxn=15;
long long d[2][1<<maxn],memo[maxn*maxn][maxn*maxn];
void update(int a,int b){
    if(b&(1<<m)) d[cur][b^(1<<m)]+=d[1-cur][a];
}
int main(){
 memset(memo,-1,sizeof(memo));
    while(scanf("%d%d",&n,&m)==2){
     if(n<m) swap(n,m);
  if(memo[n][m]>=0){
   printf("%lld\n",memo[n][m]);
   continue;
  }else{
  memset(d,0,sizeof(d));
  cur=0;
  d[0][(1<<m)-1]=1;
  for(int i=0;i<n;i++)
   for(int j=0;j<m;j++){
       cur^=1;
    memset(d[cur],0,sizeof(d[cur]));
    for(int k=0;k<(1<<m);k++){
        update(k,k<<1);
     if(i&&!(k&(1<<(m-1)))) update(k,(k<<1)|(1<<m)|1);
     if(j&&!(k&1)) update(k,(k<<1)|3);
    }
   }
   printf("%lld\n",memo[n][m]=d[cur][(1<<m)-1]);
  }
 }
 return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值