zoukankan      html  css  js  c++  java
  • NOI 2001 炮兵阵地

    洛谷 P2704 [NOI2001]炮兵阵地

    洛谷传送门

    JDOJ 1105: 炮兵阵地

    JDOJ1105传送门

    JDOJ 1508: [NOI2001]炮兵阵地

    JDOJ1508传送门

    Description

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

    img

    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。 图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。  

    现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内) ,在整个地图区域内最多能够摆放多少我军的炮兵部队。

    Input

    第一行包含两个由空格分割开的正整数,分别表示N和M; 接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。 N≤100;M≤10。

    Output

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

    Sample Input

    5 4 PHPP PPHH PPPP PHPP PHHP

    Sample Output

    6

    题解:

    众所周知,这是一道状压(DP)的题目。

    众所周知,设计状态的时候要考虑边界。

    不能死脑筋,一做状压就想之前的题只设计了前面一个状态来转移,这道题不一样。为什么呢?就像斐波那契数列的递推式:(f[i]=f[i-1]+f[i-2])。这个转移是和前两个数有关的。同理,因为这台意大利炮能打前面两格,所以设计状态的时候自然就要把两个状态压进去:现在的和前一个。

    那么由此得出状态:

    (dp[i][j][k])表示行数为(i)、当前状态为(j)、上一状态为(k)时的最大炮数。

    这里状态0/1表示的不是能不能被炮攻击到,而只是单纯的有没有炮(如果按前面的设置状态的话没法统计答案)。

    然后我们考虑转移的条件。有两个条件限制了我们转移:第一种是本来就不能放大炮。即山地的情况。第二种是因为容易被其他大炮打到,所以不能放大炮。

    类比于USACO玉米田的一道题,我们可以在输入的时候直接处理出初始状态,即山地肯定不能放炮。用(F[i])数组存储。

    但是我们发现了一个问题。。这么设置状态所需的空间是:100 *1024 *1024。。必爆无疑。

    怎么办呢?

    在此介绍动态规划中的常用优化方法:滚动数组

    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,m,cnt;
    int map[110][20];
    int dp[110][70][70];
    int F[110];
    int num[110],st[110];
    //dp[i][j][k]表示行数为i,状态为j、上一行状态为k的时候最多摆放的炮兵部队的个数。
    int lowbit(int x)
    {
        int ret=0;
        while(x)
        {
            x-=(x&(-x));
            ret++;
        }
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                char a;
                cin>>a;
                if(a=='H')
                    map[i][j]=1;
                F[i]=(F[i]<<1)+map[i][j];
            }
        st[++cnt]=0;
        for(int i=1;i<(1<<m);i++)
        {
            if(i&(i<<1))
                continue;
            if(i&(i<<2))
                continue;
            if(i&(i>>1))
                continue;
            if(i&(i>>2))
                continue;
            st[++cnt]=i;
            int tmp=i;
            num[cnt]=lowbit(tmp);
        }
        for(int i=1;i<=cnt;i++)
            if((st[i]&F[1])==0)
                dp[1][i][0]=num[i];
        for(int i=1;i<=cnt;i++)
            if((st[i]&F[2])==0)
                for(int j=1;j<=cnt;j++)
                    if((st[i]&st[j])==0 && (st[j]&F[1])==0)
                        dp[2][i][j]=num[i]+num[j];
        for(int i=3;i<=n;i++)
            for(int j=1;j<=cnt;j++)
                if((st[j]&F[i])==0)
                    for(int k1=1;k1<=cnt;k1++)
                        if((st[j]&st[k1])==0 && (st[k1]&F[i-1])==0)                  
                            for(int k2=1;k2<=cnt;k2++)             
                                if((st[j]&st[k2])==0 && (st[k1]&st[k2])==0 && (st[k2]&F[i-2])==0)
                                    dp[i][j][k1]=max(dp[i][j][k1],dp[i-1][k1][k2]+num[j]);
        int ans=0;
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=cnt;j++)
                ans=max(ans,dp[n][i][j]);
        printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    108. Convert Sorted Array to Binary Search Tree
    107. Binary Tree Level Order Traversal II
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    104. Maximum Depth of Binary Tree
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    系统和进程相关信息
    文件I/0缓冲
    系统编程概念(文件系统mount等函数的使用)
  • 原文地址:https://www.cnblogs.com/fusiwei/p/11817416.html
Copyright © 2011-2022 走看看