NOI 2001 炮兵阵地


【分析】
本来想的和周伟nei胖子差不多…但是感觉时间会炸,于是又苟且看了讲解…发现胖子果然用会炸的方法…但是毕竟十几年前的题了…数据略弱(。・・)ノ

dp[i][j][k]表示前i行中,第i行状态为j,第i-1行状态为k时炮兵的最多数量(状态均为01的二进制串)。方程很好写: dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]),num[j]代表状态j的炮兵数量,比如num[10101]=3。把jkl都枚举一下就行(虽然时间上趋近于炸)。

至于预处理,留给读者思考吧。(先找出所有不合法的相邻与隔一个相邻的状态标记,然后再处理合法状态中占有山地的状态…具体用暴力实现。复杂度一千W)


【代码】

//NOI 2001 廉渊升的阵地(炮兵阵地)
#include<cmath> 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
int n,m,p,ans;
bool b[1<<10],can[105][12],ok[105][1<<10];
int num[1<<10],dp[2][1<<10][1<<10]; //前i行,且第i行为状态j时,第i-1行为k时 的最多人数 
inline void init()
{
    int ttt[15],change[1<<11];
    int i,j,k,s;
    char c;
    scanf("%d%d",&n,&m);
    fo(i,1,n) fo(j,1,m) {cin>>c;if(c=='P') can[i][j]=1;}
    fo(i,0,10) change[1<<i]=i+1;
    fo(s,0,(1<<m)-1)
    {
        int now=s,next=0,c=0;
        while(now)
        {
            int tmp=now&-now;
            if(tmp==next*2 || tmp==next*4) break;
            now-=tmp;
            next=tmp;
            ttt[++c]=change[tmp];
        }
        if(!now) 
        {
            b[s]=1,num[s]=c;
            fo(i,1,n)
            {
                bool flag=1;
                fo(j,1,m) if(!can[i][j])
                {
                    if(!flag) break;
                    fo(k,1,c)
                      if(ttt[k]==j)
                      {flag=0;break;} 
                }
                if(flag) ok[i][s]=1;
            }
        }
    }
}
int main()
{
    int i,j,k,s,now,pre,l;
    init();
    now=1;
    fo(j,0,(1<<m)-1) if(b[j] && ok[1][j]) dp[1][j][0]=num[j];
    fo(i,2,n)
    {
        now=i&1,pre=now^1;
        memset(dp[now],0,sizeof dp[now]);
        fo(j,0,(1<<m)-1) if(b[j] && ok[i][j])
          fo(k,0,(1<<m)-1) if(b[k] && ok[i-1][k] && (j&k)==0)
            fo(l,0,(1<<m)-1) if(b[l] && (i==2||ok[i-2][l]) && (j&l)==0)
              dp[now][j][k]=max(dp[now][j][k],dp[pre][k][l]+num[j]);
    }
    fo(j,0,(1<<m)-1)
      fo(k,0,(1<<m)-1)
        ans=max(ans,dp[now][j][k]);
    printf("%d\n",ans);
    return 0;
}
//5 4
//PHPP
//PPHH
//PPPP
//PHPP
//PHHP
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值