zoukankan      html  css  js  c++  java
  • poj1185

    题意:给出一张n*m的地图,'H'表示高地,不能部署炮兵,'P'表示平原,可以部署炮兵,炮兵之间必须保持横向、纵向至少2个格子的距离,保证没有误伤。问最多可以部署多少炮兵。

    分析:

    1.可以用一个32位整数存每一行的状态(二进制上1表示有布置炮兵,0表示没有布置炮兵),由于每一行的状态都要前两行的状态来决定,因此真正的一个状态应该包含本行的状态和上一行的状态,用dp[x][i][j]表示第x行上状态i,x-1行状态为j的最优解。

    2.每一行的状态其实只有60种,可以直接暴力搜索出来,把这60种状态按二进制递增顺序(排序目的是方便确定状态没有超出n*m的范围)存到数组state[]中,计算好每种状态中能部署炮兵的数目,存到get[]数组。

    3.地图转换成一个二进制的数组,即一个整数表示一行的地形(1表示高地,0表示平原)。因此一个状态能否存在的一个条件是state[i] & map[x] == 0,这样是合法的.

    4.状态转移方程为dp[x][i][j] = max(dp[x - 1][j][k] + get[i],dp[x][i][j]),条件是state[i] & map[x] == 0 ,state[i] & state[j] == 0,state[i] & state[k] == 0,而且存在dp[x - 1][j][k]。把不存在的dp[x][i][j]标为-1.

    PS:看了discuss发现还可以用最大点独立集来做。

    #include <cstdio>
    #include <algorithm>
    using std::sort;
    int n,m,state[60],get[60],ts = 0;
    void search_bruce(int bgn,int s)
    {
        if(bgn == 10)
        {
            state[ts++] = s;
            return;
        }
        for(int i = 0;i < 2;i++)
        {
            if(i == 1 && bgn > 0 && (((1 << (bgn - 1))) & s) != 0)
                continue;
            if(i == 1 && bgn > 1 && (((1 << (bgn - 2))) & s) != 0)
                continue;
            search_bruce(bgn + 1,( i << bgn) | s);
        }
        return;
    }
    
    void counter()
    {
        for(int i = 0;i < 60;i++)
        {
            get[i] = 0;
            for(int j = 0;j < 10;j++)
            {
                if((state[i] & (1 << j)) != 0)
                    get[i]++;
            }
        }
    }
    bool conflict(int a,int b)
    {
        if((a & b) == 0)
            return false;
        else
            return true;
    }
    int main()
    {
        search_bruce(0,0);
        sort(state,state + ts);
        counter();
        int n,m,map[100],dp[2][60][60],td;
        while(~scanf("%d%d",&n,&m))
        {
            for(int i = 0;i < n;i++)
                map[i] = 0;
            for(int i = 0;i < n;i++)
            {
                getchar();
                for(int j = 0;j < m;j++)
                {
                    char c;
                    scanf("%c",&c);
                    if(c == 'H')
                        map[i] = (map[i] | (1 << j));
                }
            }
            int maximum = 1 << m;
            for(int i = 0;i < 60 && state[i] < maximum;i++)
            {
                for(int j = 0;j < 60 && state[j] < maximum;j++)
                {
                    dp[0][i][j] = -1;
                }
            }
            dp[0][0][0] = 0;
            for(td = 1;td <= n;td++)
            {
                int now = td % 2,before = (td + 1) % 2;
                for(int i = 0;i < 60 && state[i] < maximum;i++)
                {
                    for(int j = 0;j < 60 && state[j] < maximum;j++)
                    {
                        if(conflict(state[i],map[td - 1]) || conflict(state[i],state[j]))
                        {
                            dp[now][i][j] = -1;
                            continue;
                        }
                        dp[now][i][j] = 0;
                        for(int k = 0;k < 60 && state[k] < maximum;k++)
                        {
                            if(conflict(state[i],state[k]) || dp[before][j][k] == -1)
                                dp[now][i][j] = std::max(dp[now][i][j],get[i]);
                            else
                                dp[now][i][j] = std::max(dp[now][i][j],dp[before][j][k] + get[i]);
                        }
                    }
                }
            }
    
            int max = 0;
            td = (td + 1) % 2;
            for(int i = 0;i < 60 && state[i] < maximum;i++)
            {
                for(int j = 0;j < 60 && state[j] < maximum;j++)
                    max = std::max(max,dp[td][i][j]);
            }
            printf("%d\n",max);
        }
        return 0;
    }
  • 相关阅读:
    LeetCode:204. 计数质数
    LeetCode:203. 移除链表元素
    LeetCode:202. 快乐数
    LeetCode:191. 位1的个数
    LeetCode:190. 颠倒二进制位
    LeetCode:189. 旋转数组
    LeetCode:187. 重复的DNA序列
    LeetCode:165. 比较版本号
    LeetCode:164. 最大间距
    LeetCode:155. 最小栈
  • 原文地址:https://www.cnblogs.com/ZShogg/p/3072534.html
Copyright © 2011-2022 走看看