• POJ1185状态压缩DP


    难得的中文题.

    POJ1185http://poj.org/problem?id=1185

    方法就是用DP[i][r][p]表示第i行状态为r,第i-1行状态是p时的最多个数。而这里p受到r的限制,而第i-2行状态q则受到r和p两个状态限制。状态转移方程就是:

                 DP[i][r][p] = MAX{DP[i-1][p][q] +num[r]}

    其中,p是受到r的限制时枚举的状态,q是受到r和p共同限制时候的状态,num[r]表示状态r里面的布局炮兵所摆的个数。

    这里我们可以看到就要枚举i,r,p,q,这4 个变量,i的范围是100,而其他几个则都是1<<10,复杂度颇为偏高。而实际上由于每一行里面有很多都是某些位置被其他位置影响的。比如:   1110001,  如果第一个位置放上炮兵,那么第二第三的位置都会受到影响,而一个也放不了。

    解决方案就是不去管那些相互有影响的状态,把形如:

    1000000    0100000    ... ...

    1001000    0100001    ... ...

    ...

    1001001

    这些相互之间没有影响的状态找出来,这样所有的状态数就会减少至少于60种(我算了一下,好像是58种),这样一来就是60*60*60*100,可以过了。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #define mem(a) memset(a,0,sizeof(a))
     4 #define MAX(a,b) ((a) > (b) ? (a) : (b))
     5 
     6 int DP[2][60][60],num1[60],s[60],row[105];
     7 int N,M,StateNum;//StateNum记录不会产生冲突的状态数目
     8 
     9 bool Judge(int x)//判断状态x是否存在有相邻或相隔为2的1,没有返回true
    10 {
    11     if(x & (x<<1)) return false;
    12     if(x & (x<<2)) return false;
    13     return true;
    14 }
    15 
    16 int NumOf1(int x)//统计x里面1的个数
    17 {
    18     int num = 0;
    19     while(x) {
    20         num++;
    21         x &= ~(-x);
    22     }
    23     return num;
    24 }
    25 
    26 void Get_Num1_s()//给num1数组和s数组赋值
    27 {
    28     StateNum = 0;
    29     for(int i = 0 ; i < (1<<M) ; i ++ ) if(Judge(i))//从所有的状态中找出不会产生冲突的状态
    30     {
    31         s[StateNum] = i;//记录这些状态
    32         num1[StateNum] = NumOf1(i);//和这些状态1的个数
    33         StateNum ++ ;
    34     }
    35 }
    36 
    37 int main()
    38 {
    39     while(~scanf("%d%d%*c", &N, &M))
    40     {
    41         char str[15];
    42         memset(DP,-1,sizeof(DP));
    43         for(int i=1;i<=N;i++)
    44         {
    45             scanf("%s", str);
    46             for(int j=0;j<M;j++)
    47             {
    48                 if(str[j]=='P') row[i] |= (1<<j);//row记录每一行可行状态
    49             }
    50         }
    51 
    52         Get_Num1_s();
    53 
    54         for(int i=0;i<StateNum;i++) if( !(s[i] & ~row[1]) )//给第一组状态赋初值
    55         {
    56             DP[0][i][0] = num1[i];
    57         }
    58         int key = 0;
    59         for(int i=2;i<=N;i++)//枚举每一行
    60         {
    61             key = !key;
    62             for(int r=0;r<StateNum;r++) if( !(s[r] & ~row[i]) )//枚举当前行的状态,且属于当前行里
    63             {
    64                 for(int p=0;p<StateNum;p++) if( !(s[p] & s[r]) )//枚举上一行的状态,且和当前行没有冲突
    65                 {
    66                     for(int q=0;q<StateNum;q++) if( !(s[q] & (s[r]|s[p])) )//枚举上上行,且与上两行没有冲突
    67                     {
    68                         if(DP[!key][p][q] != -1)//必须是合法的状态才可以被记录在内
    69                         {
    70                             DP[key][r][p] = MAX(DP[key][r][p], DP[!key][p][q]+num1[r]);
    71                         }
    72                     }
    73                 }
    74             }
    75         }
    76         int ans = 0;
    77         for(int i=0;i<StateNum;i++)
    78         {
    79             for(int j=0;j<StateNum;j++)
    80             {
    81                 ans = MAX(ans, DP[key][i][j]);
    82             }
    83         }
    84         printf("%d
    ", ans);
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    Java对象序列化文件追加对象的问题,以及Java的读取多个对象的问题解决方法。
    解决chrome在docky上的图标模糊或不能锁定的问题
    获取表单中的输入内容、单选按钮、复选框的输入内容
    用idea写servlet文件
    get方法和post方法
    解决Only a type can be imported. com.mysql.jdbc.Connection resolves to a package的报错问题
    idea中如何配置tomcat
    JDBC中的PreparedStatement
    JDBC中的ResultSet
    JDBCl链接中Statement
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/3273321.html
Copyright © 2020-2023  润新知