• hihoCoder 1048 : 状态压缩·二


    题目链接http://hihocoder.com/problemset/problem/1048

    题目大意:用1*2或者2*1的方块铺满一个N*M的大方格,共有多少种方法。结果对1e9+7取余。2<=N<=1000, 3<=m<=5

    解题思路:挑战程序设计竞赛上有基本上一样的题目,可以参考,原题中也有提示。大致思路就是,如果从左往右铺的话,那么对第i行j列的方块来说,第i-1行的方块一定全部铺过,第j+2行的一定没有铺过。所以我们可以保存第i行和第i+1行的状态,然后递推。又由于m<=5,所以可以将两行的状态压缩成整数。具体递推过程:

     1 int t = 0;                                                                
     2 //位置(i, j)已经被铺                                                     
     3 if(s1 & (1 << k)){                                                        
     4     if(j < m) t = dp[i][j + 1][s1][s2];            //由下一个方块递推         
     5     else if(i < n) t = dp[i + 1][1][s2][0];        //从下一行第一个递推     
     6     else t = 0;                                                            
     7 }                                                                        
     8 else{                                                                    
     9     if(j < m && !(s1 & (1 << (k - 1))))         //可以横着铺             
    10         t += dp[i][j][s1 | (1 << k - 1) | (1 << k)][s2];                
    11     t %= mod;                                                            
    12     if(i < n && !(s2 & (1 << k)))                 //可以竖着铺             
    13         t += dp[i][j][s1 | (1 << k)][s2 | (1 << k)];                    
    14     t %= mod;                                                            
    15 }                                                                        
    16 dp[i][j][s1][s2] += t % mod;                                            

    完整代码:

     1 const int maxn = 1e3 + 5;
     2 int n, m;
     3 int dp[maxn][6][35][35];
     4 
     5 void solve(){
     6     memset(dp, 0, sizeof(dp)); 
     7     for(int s2 = (1 << m) - 1; s2 >= 0; s2--) dp[n][m][(1 << m) - 1][s2] = 1;
     8     for(int i = n; i >= 1; i--){
     9         for(int j = m; j >= 1; j--){
    10             int k = m - j;
    11             for(int s1 = (1 << m) - 1; s1 >= 0; s1--){
    12                 for(int s2 = (1 << m) - 1; s2 >= 0; s2--){
    13                     int t = 0;                                                                
    14                     //位置(i, j)已经被铺                                                     
    15                     if(s1 & (1 << k)){                                                            
    16                         if(j < m) t = dp[i][j + 1][s1][s2];            //由下一个方块递推         
    17                         else if(i < n) t = dp[i + 1][1][s2][0];        //从下一行第一个递推     
    18                         else t = 0;                                                            
    19                     }                                                                        
    20                     else{                                                                    
    21                         if(j < m && !(s1 & (1 << (k - 1))))         //可以横着铺             
    22                             t += dp[i][j][s1 | (1 << k - 1) | (1 << k)][s2];                
    23                         t %= mod;                                                            
    24                         if(i < n && !(s2 & (1 << k)))                 //可以竖着铺             
    25                             t += dp[i][j][s1 | (1 << k)][s2 | (1 << k)];                    
    26                         t %= mod;                                                            
    27                     }                                                                        
    28                     dp[i][j][s1][s2] += t % mod;                                            
    29                 }
    30             }
    31         }
    32     }
    33     printf("%d
    ", dp[1][1][0][0]);
    34 }
    35 int main(){
    36     scanf("%d %d", &n, &m);
    37     solve();
    38 }

    题目:

    #1048 : 状态压缩·二

    时间限制:10000ms
    单点时限:1000ms
    内存限制:256MB

    描述

    历经千辛万苦,小Hi和小Ho终于到达了举办美食节的城市!虽然人山人海,但小Hi和小Ho仍然抑制不住兴奋之情,他们放下行李便投入到了美食节的活动当中。美食节的各个摊位上各自有着非常多的有意思的小游戏,其中一个便是这样子的:

    小Hi和小Ho领到了一个大小为N*M的长方形盘子,他们可以用这个盒子来装一些大小为2*1的蛋糕。但是根据要求,他们一定要将这个盘子装的满满的,一点缝隙也不能留下来,才能够将这些蛋糕带走。

    这么简单的问题自然难不倒小Hi和小Ho,于是他们很快的就拿着蛋糕离开了~

    但小Ho却不只满足于此,于是他提出了一个问题——他们有多少种方案来装满这个N*M的盘子呢?

    值得注意的是,这个长方形盘子的上下左右是有区别的,如在N=4, M=3的时候,下面的两种方案被视为不同的两种方案哦!

    提示:我们来玩拼图吧!不过不同的枚举方式会导致不同的结果哦!

    输入

    每个测试点(输入文件)有且仅有一组测试数据。

    每组测试数据的第一行为两个正整数N、M,表示小Hi和小Ho拿到的盘子的大小。

    对于100%的数据,满足2<=N<=1000, 3<=m<=5。<>

    输出

    考虑到总的方案数可能非常大,只需要输出方案数除以1000000007的余数。

    样例输入
    2 4
    
    样例输出
    5
  • 相关阅读:
    C++11特性
    DBC文件小结
    关于宏定义
    CentOS 6.5下Zabbix的安装配置
    CentOS下搭建LAMP环境详解
    VS2010中汉字拷贝到Word出现乱码问题解决
    DLL注入
    数组赋值
    CDC的StretchBlt函数载入位图时图片失真问题
    2019年下半年Web前端开发初级理论考试
  • 原文地址:https://www.cnblogs.com/bolderic/p/7487674.html
Copyright © 2020-2023  润新知