poj-1185 炮兵阵地

12 篇文章 0 订阅

中文题意不解释,由于一行最多10位也就是一行中所有状态只有1000+,并且根据题目描述每一个炮的周围左右两位是不能放第二个的,所以我们可以再缩小状态数量,最后大约60+。炮的上下也是不能放第二个炮的所以我们可以知道,当前的状态会与之前两个状态有关,由于我们缩小了可用状态的数量我们可以对于每一行,枚举当前行和前两行的状态,根据状态的相关性我们可以得到状态转移方程。dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]+num[j]])。num为该状态下,炮的数量。num数组提前打个表就行。

补充一句,改题用二维数组是不行的,状态关联层数太多,二维数组会多包涵状态。(但是题中给的数据能过~~~)

#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#define INF 0x3f3f3f3f
#define mod 100000000
using namespace std;

int mp[120];
int dp[101][70][70];
int n,m;
int main()
{
    int num[70],vnum[70],d,p=0;
    memset(num,0,sizeof(num));
    memset(dp,0,sizeof(dp));
    memset(mp,0,sizeof(mp));
    memset(vnum,0,sizeof(vnum));
    char c;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=(1<<m)-1;i++)
    {
        int x=i;
        if(!(i&i<<1)&&!(i&i<<2))
        {
           vnum[p]=i;
            while(x)
            {
                if(x%2==1) num[p]++;
                x/=2;
            }
            p++;
        }
    }
    for(int i=1;i<=n;i++)
    {
        getchar();
        for(int j=0;j<m;j++)
        {
            scanf("%c",&c);
            mp[i]<<=1;
            if(c=='H') mp[i]=mp[i]+1;
        }
    }
    for(int i=0;i<p;i++)
    {
        if(!(vnum[i]&mp[1]))
            dp[1][i][0]=num[i];
    }
    int i,j,k,l;
    for(i=2;i<=n;++i)
    {
        for(j=0;j<p;++j)
        {
            if(!(vnum[j]&mp[i]))
            {
                if(!(vnum[j]&vnum[j]<<1))
                {
                    if(!(vnum[j]&vnum[j]<<2)){
                    for(k=0;k<p;++k)
                    {
                        if(!(vnum[k]&mp[i-1]))
                        {
                            if(!(vnum[j]&vnum[k]))
                            {
                                for(l=0;l<p;++l)
                                {
                                    if(!(vnum[l]&mp[i-2])){
                                        if(!(vnum[j]&vnum[l]))
                                        {
                                            if(!(vnum[l]&vnum[k])){
                                                //d=dp[i-2][l]+num[k];
                                                dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    }
                }
            }
        }
    }
    int maxx=0;
    for(i=0;i<p;i++)
    {
        for(j=0;j<p;j++)
        {
            if(maxx<dp[n][i][j])
            maxx=dp[n][i][j];
        }
    }
    printf("%d\n",maxx);
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值