zoukankan      html  css  js  c++  java
  • poj 1185(状态压缩DP)

    poj  1185(状态压缩DP)

    题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互攻击。

    解析:可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行的状态有关,每一行用状态压缩的表示方法,0表示不

    放大炮,1表示放大炮,同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中不能有两个1的距离小于

    2(保证横着不互相攻击),这些要预先处理一下。然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要开

    个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两

    行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数) 

    状态表示:dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。 

    状态转移方程:dp[i][j][k] =max(dp[i][j][k],dp[i-1][l][j]+cot[k]); cot[k]为k状态中1的个数 ,可用位运算求得

    DP边界条件:dp[1][0][i] =cot[i] 状态i能够满足第一行的硬件条件

    AC代码如下:

     1 #include<stdio.h>
     2 int sta[1<<11],cot[1<<11],cur[105],dp[105][105][105];
     3 char g[105][15];
     4 int n,m,num;
     5 int max(int a,int b)
     6 {
     7     return a>b?a:b;
     8 }
     9 void init()     //预处理所有可能出现的状态
    10 {
    11     int i,tmp,sum,count;
    12     num=0;
    13     sum=1<<m;
    14     for(i=0;i<sum;i++)
    15     {
    16         if(i&(i<<1) || i&(i<<2))    //同一行中1的距离不能小于2
    17             continue;
    18         sta[num]=i;
    19         count=0;
    20         tmp=i;
    21         while(tmp)      //求该状态中的二进制表示中1的个数
    22         {
    23             count++;
    24             tmp&=(tmp-1);  //将最低位的1化为0
    25         }
    26         cot[num++]=count;
    27     }
    28 }
    29 int fit(int x,int y)   //判断上下两行对应位置是否同为1
    30 {
    31     if(x&y)
    32         return 0;
    33     return 1;
    34 }
    35 void DP()
    36 {
    37     int i,j,k,l;
    38     for(i=0;i<num;i++)    //预处理第1行的情况
    39     {
    40         if(!fit(sta[i],cur[1]))
    41             continue;
    42         dp[1][0][i]=cot[i];
    43     }
    44     for(i=2;i<=n;i++)
    45     {
    46         for(j=0;j<num;j++)
    47             for(k=0;k<num;k++)
    48             {
    49                 if(!fit(sta[k],cur[i]) || !fit(sta[j],cur[i-1]) || !fit(sta[k],sta[j]))   //排除不符合条件的状态
    50                     continue;
    51                 for(l=0;l<num;l++)
    52                 {
    53                     if(!fit(sta[l],cur[i-2]) || !fit(sta[k],sta[l]) || !fit(sta[j],sta[l]) || !dp[i-1][l][j])   //排除不符合条件的状态
    54                         continue;
    55                     dp[i][j][k]=max(dp[i][j][k],dp[i-1][l][j]+cot[k]);   //状态转移
    56                 }
    57             }
    58     }
    59     int ans=0;
    60     for(i=1;i<=n;i++)   //求最多放置多少大炮
    61         for(j=0;j<num;j++)
    62             for(k=0;k<num;k++)
    63                 ans=max(ans,dp[i][j][k]);
    64     printf("%d
    ",ans);
    65 }
    66 int main()
    67 {
    68     int i,j;
    69     char c;
    70     scanf("%d%d",&n,&m);
    71     for(i=1;i<=n;i++)
    72     {
    73         getchar();
    74         for(j=1;j<=m;j++)
    75         {
    76             scanf("%c",&c);
    77             if(c=='H')          //用二进制表示不能放置大炮的情况,便于判断
    78                 cur[i]+=1<<(m-j);   //网上大多数的题解都是cur[i]+=1<<(j-1);反过来了,我表示很不理解,但是能AC =_=||~~~
    79         }
    80     }
    81     init();
    82     DP();
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    windows下python-nmap运行过程中出现的问题及解决办法
    命令行下cl.exe编译链接的问题及解决方法
    httrack: error while loading shared libraries: libhttrack.so.2的解决方法
    AES加解密非固定长度文本的用法
    John the Ripper password cracker试用
    ubuntu12.04使用root登陆的简单设置
    map按value查找相应元素
    ListCtrl添加右键菜单(ListCtrl类里编辑,给ListCtrl 发送NM_RCLICK消息)
    今天发现里一个非常好用的Listbox自绘类,带不同文字字体和图片,觉得很有必要记下来
    自绘listCtrl控件选中该行高亮(模拟windows)
  • 原文地址:https://www.cnblogs.com/frog112111/p/3236568.html
Copyright © 2011-2022 走看看