zoukankan      html  css  js  c++  java
  • poj2411 Mondriaan's Dream ***

      1 /* 状态压缩DP , 类似炮兵阵地(POJ1185,本blog有。。)
    2 *
    3 * 自己写的,判断是否合法写的很长。。。
    4 *
    5 * 贴个"解题报告"吧。。
    6 *
    7 Assume you could calculate the number of different paintings
    8 for a rectangle with c columns and r rows where the first r-1
    9 rows are completely filled and the last row has any of 2c
    10 possible patterns. Then, by trying all variations of filling
    11 the last row where small rectangles may be spilled into a further
    12 row, you can calculate the number of different paintings for a
    13 rectangle with r+1 rows where the first r rows are completely
    14 filled and the last row again has any pattern.
    15
    16 This straightforwardly leads to a dynamic programming solution.
    17 All possible ways of filling a row part of which may already be
    18 occupied and spilling into the next row creating a new pattern
    19 are genrated by backtracking over a row. Viewing these as
    20 transitions from a pattern to another pattern, their number
    21 is given by the recursive equation Tc = 2 Tc-1 + Tc-2. Its
    22 solution is asymptotically exponential with a base of sqrt(2)+1,
    23 which is not a problem for c<=11.
    24
    25 If both h and w are odd, the result is 0. Since the number of
    26 paintings is a symmetric function, the number of columns
    27 should be chosen as the smaller of the two input numbers
    28 whenever possible to improve run-time behaviour substantially.
    29
    30 Judges' test data includes all 121 legal combinations of h and w.
    31 *
    32 *
    33 * 后面贴两个暴强25行代码(见POJ discuss)
    34 *
    35 *
    36 */
    37
    38 #include <cstdio>
    39 #include <cstring>
    40 using namespace std;
    41
    42 const int maxs = (1 << 11) + 5;
    43 const int maxn = 11 + 3;
    44
    45 int n, m;
    46 long long dp[maxn][maxs];
    47 long long ansRec[maxn][maxn];
    48
    49 bool check(int cur){
    50 for(int i=0; i<m; i++){
    51 if(((cur>>i)&1)){
    52 if(i==m-1 || (!((cur)>>(i+1)&1)))
    53 return false;
    54 i++;
    55 }
    56 }
    57 return true;
    58 }
    59
    60 //cur: 当前行状态
    61 //last:上一行状态
    62 bool isOk(int cur, int last){
    63 for(int i=0; i<m; i++){
    64 if(!(cur&(1<<i))){
    65 if(!(last&(1<<i)))
    66 return false;
    67 }
    68 else{
    69 if(!(last&(1<<i))) continue;
    70 if(i==m-1 || (!(last&(1<<(i+1)))) || (!(cur&(1<<(i+1)))) )
    71 return false;
    72 i++;
    73 }
    74 }
    75 return true;
    76 }
    77
    78 int main(){
    79 //记录答案
    80 memset(ansRec, -1, sizeof(ansRec));
    81
    82 while(scanf("%d%d", &n, &m)){
    83 if(n == 0) return 0;
    84
    85 //奇数
    86 if((n % 2 != 0) && (m % 2 != 0)){
    87 printf("0\n");
    88 continue;
    89 }
    90 //已算
    91 if(ansRec[m][n] != -1){
    92 printf("%lld\n", ansRec[m][n]);
    93 continue;
    94 }
    95 //用较小的数做列
    96 int tmp;
    97 if(n < m){
    98 tmp = n;
    99 n = m;
    100 m = tmp;
    101 }
    102
    103 //初始化
    104 memset(dp, 0, sizeof(dp));
    105
    106 //the first line
    107 for(int i=0; i<(1<<m); i++){
    108 if(check(i))
    109 dp[0][i] = 1;
    110 }
    111
    112 //dp
    113 for(int i=1; i<n; i++){
    114 for(int j=0; j<(1<<m); j++){
    115 for(int k=0; k<(1<<m); k++)
    116 if(isOk(j, k)){
    117 dp[i][j] += dp[i-1][k];
    118 }
    119 }
    120 }
    121
    122 printf("%lld\n", dp[n-1][(1<<m)-1]);
    123 ansRec[n][m] = ansRec[m][n] = dp[n-1][(1<<m)-1];
    124 }
    125
    126 return 0;
    127 }

      

    //25行代码-1

     1 /*
    2 用2进制的01表示不放还是放
    3 第i行只和i-1行有关
    4 枚举i-1行的每个状态,推出由此状态能达到的i行状态
    5 如果i-1行的出发状态某处未放,必然要在i行放一个竖的方块,
    6 所以我对上一行状态按位取反之后的状态就是放置了竖方块的状态。
    7 然后用搜索扫一道在i行放横着的方块的所有可能,
    8 并且把这些状态累加上i-1的出发状态的方法数,如果该方法数为0,
    9 直接continue。
    10
    11 举个例子
    12 2 4
    13 1111
    14 1111
    15 状态可以由
    16 1100 0000 0110 0011 1111
    17 0000 0000 0000 0000 0000
    18 这五种i-1的状态达到,故2 4 的答案为5
    19
    20 */
    21
    22 #include<cstdio>
    23 #include<cstring>
    24 long long f[30][1<<12],i,j,n,m,saya=1;
    25 void sayatime (int i,int s1,int pos)
    26 {
    27 if (pos==m) {f[i][s1]+=saya;return;}
    28 sayatime(i,s1,pos+1);
    29 if (pos<=m-2&&!(s1&1<<pos)&&!(s1&1<<pos+1)) sayatime(i,s1|1<<pos|1<<pos+1,pos+2);
    30 }
    31 int main()
    32 {
    33
    34 while(scanf("%d%d",&n,&m),n!=0)
    35 {
    36 memset(f,0,sizeof(f));saya=1;
    37 sayatime(1,0,0);
    38 for (i=2;i<=n;i++)
    39 for (j=0;j<1<<m;j++)
    40 {
    41 if (f[i-1][j]) saya=f[i-1][j]; else continue;
    42 sayatime(i,~j&((1<<m)-1),0);
    43 }
    44 printf("%lld\n",f[n][(1<<m)-1]);
    45 }
    46 }

      

    //25行代码-2

     1 /*
    2 p、c是滚动数组下标
    3 */
    4
    5 #include<iostream>
    6 #include<cstring>
    7 using namespace std;
    8 long long f[2][1<<12],i,j,ps,p=0,c=1,n,m;
    9 int main()
    10 {
    11 while (scanf("%d%d",&n,&m),n!=0)
    12 {
    13 memset(f[c],0,sizeof(f[c]));
    14 f[c][(1<<m)-1]=1;
    15 for (i=0;i<n;i++)
    16 for (j=0;j<m;j++)
    17 {
    18 swap(p,c);memset(f[c],0,sizeof(f[c]));
    19 for (ps=0;ps<1<<m;ps++)
    20 if (f[p][ps])
    21 {
    22 if (j>0&&(!(ps&(1<<j-1)))&&(ps&(1<<j))) f[c][ps|1<<(j-1)]+=f[p][ps];
    23 if (!(ps&1<<j)) f[c][ps|1<<j]+=f[p][ps];
    24 if (ps&1<<j) f[c][ps^1<<j]+=f[p][ps];
    25 }
    26 }
    27 printf("%lld\n",f[c][(1<<m)-1]);
    28 }
    29 }




  • 相关阅读:
    java时间戳与Date相互转换、日期格式化、给日期加上指定时长、判断两时间点是否为同一天
    notepad++去掉红色波浪线
    发生异常Address already in use: bind
    SecureCRT背景颜色
    linux查看实时日志命令
    idel上传代码到github时遇到的Push rejected: Push to origin/master was rejected
    git解决error: The following untracked working tree files would be overwritten by checkout
    使用SecureCRT工具上传、下载文件的两种方法
    Windows下Zookeeper启动zkServer.cmd闪退问题的解决方案
    Maven的Snapshot版本与Release版本
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2417866.html
Copyright © 2011-2022 走看看