poj 1185 炮兵阵地 【状态压缩dp】

原题链接 poj 1185 炮兵阵地

       由于每行只有十个可以考虑用状态压缩,又由于每行两炮之间不能小于2,故可以先计算出,最多不会超过60种

状态,可以先存下这些状态(f[]),然后存下每种状态的炮阵地数量(num[]),用dp[][][];

 状态转移公式 dp[i][j][k]=num[j]+max(dp[i-1][k][t])(其中j与k相符,j与t也要相符) (ps:相符是指,同一列 两者的阵地不能相冲)

我是新手 代码有危险:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1<<10
using namespace std;
char map[105][12];
int dp[105][66][66];//dp[i][j][k]第i行,取第j种状态且上一行取第k种状态
int f[62];//存的是所有可能的状态值
int num[62];//每种状态对应的摆放数。
int n,m;
bool check(int p1,int u)//初始化中保证每行不能有两个相差小于2
{
    int tt=2;
    int nu=0;
    for(int i=0; i<m; i++)
    {
        if((u>>i)&1)
        {
            nu++;
            if(tt<2)return false;
            tt=0;
            continue;
        }
        tt++;
    }
    num[p1]=nu;
    return true;
}
void init()//初始化出所有可能的状态,不考虑地形的。。。
{
    int p1=0;
    for(int i=0; i<(1<<m); i++)
        if(check(p1,i))
            f[p1++]=i;
     f[p1]=(1<<m);
}

bool ck(int s,int u)
{
    for(int i=0; i<m; i++)
        if(((u>>i)&1)&&map[s][i]=='H')
            return false;
    return true;
}

int pk(int i,int j,int k)
{
    int ans=0;
     for(int t=0;f[t]<(1<<m);t++)
     {
         if(f[j]&f[t])continue;
         ans=max(ans,dp[i-1][k][t]);
     }
 return ans;
}
int solve()
{
     memset(dp[1],0,sizeof(dp[1]));
    for(int i=0;f[i]<(1<<m); i++)//对dp初始化
        if(ck(1,f[i]))
            dp[1][i][0]=num[i];
        else
            dp[1][i][0]=0;

    for(int i=2;i<=n;i++)  //当前是第几行
    {
         for(int j=0;f[j]<(1<<m);j++)//当前选哪个状态
         {
            for(int k=0;f[k]<(1<<m);k++) //上一行选哪个状态
            {
                 dp[i][j][k]=0;

                 if(!ck(i,f[j])||(f[j]&f[k]))continue;//根据当前地形判断此状态是否合理 以及 j和上一行的k是否相容。
                  dp[i][j][k]=num[j]+pk(i,j,k);

            }

         }
    }
    int ans=0;

  for(int i=0;f[i]<(1<<m);i++)
    for(int j=0;j<(1<<m);j++)
     ans=max(ans,dp[n][i][j]);
  return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)!=EOF)
    { getchar();
        for(int i=1; i<=n; i++)
            scanf("%s",map[i]);
        init();

        printf("%d\n",solve());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值