poj 2411 Mondriaan's Dream

题目连接:http://poj.org/problem?id=2411

这个题目用状态压缩DP很容易理解,主要是先预处理,预处理就是把第一行合法状态置1。然后枚举第i行和第i-1行的状态,在不矛盾的情况下可以相加。dp[i][k]表示第第i行状态为k时的总种数。所以最后只要输出dp[row-1][0]即可,这样保证最后一行保证填满而且不会在伸出。自己的方法简单易懂但是不够优化,时间复杂度为o(row*(1<<col)*(1<<col)),后来看了别人的解题报告发现可以优化到O(row*(1<<col)*(可行状态数))这在时间上可以优化很多。

#include <iostream> #include <cstdio> #include <cstring> using namespace std; __int64 dp[12][1<<12]; int row,col; bool isCan(int x){ int i=0; while(i<col){ if((1<<i)&x)i++; else{ if((1<<(i+1))&x)return false; if(i==(col-1))return false; i+=2; } } return true; } void init(){ memset(dp,0,sizeof(dp)); for(int i=0;i<(1<<col);i++){ if(isCan(i)){ dp[0][i]=1; } } } int main(){ while(scanf("%d%d",&row,&col)){ if(row==0 && col==0)return 0; init(); for(int i=1;i<row;i++){ for(int k=0;k<(1<<col);k++){ for(int j=0;j<(1<<col);j++){ if(k&j)continue; if(isCan(k|j)){ dp[i][k]+=dp[i-1][j]; } } } } printf("%I64d\n",dp[row-1][0]); } }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值