• POJ 2411 Mondriaan's Dream 解题报告


    POJ 2411 Mondriaan's Dream 解题报告2

    与1不同的是,没用dfs,纯dp
    思路是:
    用0表示没放,1表示放了。横放则左右两格都是1,竖放则上格是0,下格是1。
    这种记录state的方法决定了:如果上下两行的state是确定的,那么放法唯一。
    Fun(state,n)表示n这行的状态是state的时候有多少种放法。
    那么我们要求的就是Fun(2^m-1,n).
    Fun(state,n)就等于sigma Fun(last,n-1),last取遍所有可以取到的状态。
    限制last取值的因素有两个:
    1、state中是0的位置,last中一定是1,否则出现没填满的情况。
    2、把state和last取&,也就是last是0的位,state也变0,看有没有影响到state,让它出现单1不能横放。
    结束条件是n==1,且state能横放。

    还有一个要注意的问题就是结果要用64位整型保存。
      1
      2#include <cstdio> 
      3
      4const int large = 1<<11;
      5int m,n;
      6__int64 result[12][12];
      7__int64 dp[large][12];
      8int power;
      9
     10__int64 Fun( const int state, const int n )
     11{
     12    if ( n == 1 )
     13    {
     14         int flag = 1;
     15         for ( int i = 0; i < power; ++i )
     16         {
     17             if ( (state&(1<<i)) == 0 )continue;
     18             if ( i+1 == m )
     19             {
     20                  flag = 0;
     21                  break;
     22             }

     23             if ( (state&(1<<(i+1))) == 0 )
     24             {
     25                  flag = 0;
     26                  break;
     27             }

     28             ++i;
     29         }

     30         if ( flag ) return 1//若能横放
     31         return 0;
     32    }

     33    
     34     int last = ~state;//last是last状态1起码的状态 
     35     last &= ( (1<<m) -1 );//我一开始忘记了加这一句,last全都是负的,哈哈
     36     __int64 s = 0;
     37     if ( dp[state][n] != -1 ) return dp[state][n];
     38     
     39     for ( int i = 0; i < power; ++i )
     40     {
     41         int flag = 1;
     42         int tmp = state&i;
     43         if ( (i&last) != last ) continue//last限制因素1
     44         for ( int j = 0; j < m; ++j )//last限制因素2
     45         {
     46             if ( (tmp&(1<<j)) == 0 ) continue;
     47             if ( j+1 == m )
     48             {
     49                  flag = 0;
     50                  break;
     51             }

     52             if ( (tmp&(1<<(j+1))) == 0 )
     53             {
     54                  flag = 0;
     55                  break;
     56             }

     57             ++j;
     58         }

     59         if ( flag ) s+= Fun( i, n-1 );
     60     }

     61     
     62     dp[state][n] = s;
     63     return s;
     64}

     65
     66int main()
     67{
     68    while ( scanf( "%d%d"&m, &n ), !( m == 0 && n == 0 ) )
     69    {
     70          int s = 0;
     71          if ( (m*n)%2 ) //面积
     72          {
     73               puts( "0" );
     74               continue;
     75          }

     76          if ( m > n ) //使n大m小
     77          {
     78               int tmp = m;
     79               m = n;
     80               n = tmp;
     81          }

     82          if ( result[n][m] != 0 ) //算过就不要再算了
     83          {
     84               printf( "%I64d\n", result[n][m] );
     85               continue;
     86          }

     87          power = 1<<m;
     88          //初始化
     89          for ( int i = 0; i < large; ++i )
     90          {
     91              for ( int j = 0; j <= n; ++j )
     92              {
     93                  dp[i][j] = -1;
     94              }

     95          }

     96          
     97          result[n][m] = Fun( power-1, n ); //最后一行放满
     98          printf( "%I64d\n", result[n][m] );
     99    }

    100    
    101    return 0;
    102}

    103
  • 相关阅读:
    python集成开发环境Anaconda的安装
    hasMap2
    WireShark:TCP三次握手 抓包
    CCF 201409-4 最优配餐
    201403-4 无线网络
    java IO的字节流和字符流及其区别
    平衡二叉树DSW算法
    警惕Java编译器中那些“蜜糖”陷阱
    laravel 学习笔记 —— 神奇的服务容器
    LNMP下安装phpmyadmin的一个小错误解决办法
  • 原文地址:https://www.cnblogs.com/PureMilk/p/1247492.html
Copyright © 2020-2023  润新知