• TZOJ 4912 炮兵阵地(状压dp)


    描述

    司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 

    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 
    现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。 

     输入

    第一行包含两个由空格分割开的正整数,分别表示N和M;

    接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。

    输出

     仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

    样例输入

    5 4
    PHPP
    PPHH
    PPPP
    PHPP
    PHHP

    样例输出

    6

    题意

    在N*M的阵地上最多能放多少炮兵部队,要求不能出现误伤(攻击范围如上图),炮兵只能放在平原P

    题解

    状压dp经典题

    可以发现当前行由前两行状态决定,所以可以开三维数组,dp[i][j][k]代表第i行j状态和第i-1行k状态

    首先枚举所有状态存进state数组,根据题意每2个1中间至少有2个0,可以发现总数不会超过100

    状态转移方程dp[i][j][k]=dp[i-1][k][l]+sum[j](sum[j]状态j有几个炮兵)表示第i行j状态和第i-1行k状态由第i-1行k状态和第i-2行l状态转移过来

    预处理的时候要先把1和2处理出来

    代码

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 int dp[105][105][105],state[105],cur[105],sum[105];
     6 int cal(int x)
     7 {
     8     int ret=0;
     9     while(x)ret+=(x&1),x>>=1;
    10     return ret;
    11 }
    12 int main()
    13 {
    14     int n,m;
    15     char s[15];
    16     scanf("%d%d",&n,&m);
    17     for(int i=1;i<=n;i++)
    18     {
    19         scanf("%s",s+1);
    20         for(int j=1;j<=m;j++)
    21             if(s[j]=='H')
    22                 cur[i]+=1<<(m-j);
    23     }
    24 
    25     ///init
    26     int tot=0;
    27     for(int i=0;i<(1<<m);i++)
    28         if(!(i&(i<<1))&&!(i&(i<<2)))
    29             state[++tot]=i,sum[tot]=cal(i);
    30 
    31     ///1
    32     for(int i=1;i<=tot;i++)
    33         if(!(state[i]&cur[1]))
    34             dp[1][i][0]=sum[i];
    35 
    36     ///2
    37     for(int i=1;i<=tot;i++)
    38     {
    39         if(state[i]&cur[2])continue;
    40         for(int j=1;j<=tot;j++)
    41         {
    42             if(state[j]&cur[1])continue;
    43             dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+sum[i]);
    44         }
    45     }
    46     
    47     for(int i=3;i<=n;i++)
    48         for(int j=1;j<=tot;j++)///i行j状态,需要部署炮兵的状态
    49         {
    50             if(state[j]&cur[i])continue;
    51             for(int k=1;k<=tot;k++)///i-1行k状态
    52             {
    53                 if(state[k]&cur[i-1])continue;
    54                 for(int l=1;l<=tot;l++)///i-2行l状态
    55                 {
    56                     if(state[l]&cur[i-2])continue;
    57                     if((state[j]&state[k])||(state[j]&state[l])||(state[k]&state[l]))continue;
    58                     dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+sum[j]);
    59                 }
    60             }
    61         }
    62 
    63     int res=0;
    64     for(int i=1;i<=tot;i++)
    65         for(int j=1;j<=tot;j++)
    66             res=max(res,dp[n][i][j]);
    67     printf("%d
    ",res);
    68     return 0;
    69 }
  • 相关阅读:
    高手 读书笔记-1.精英社会的神话
    企业IT架构转型之道 读书笔记-1.阿里巴巴集团中台战略引发的思考
    Redis学习-内存优化
    Redis学习笔记--常用命令
    Go语言备忘录(3):net/http包的使用模式和源码解析
    Go语言备忘录(2):反射的原理与使用详解
    Go语言备忘录(1):基本数据结构
    Go的接口总结
    Go的类型断言解析
    StrangeIoc框架学习
  • 原文地址:https://www.cnblogs.com/taozi1115402474/p/9322695.html
Copyright © 2020-2023  润新知