状压dp+小优化 炮兵阵地

链接:登录—专业IT笔试面试备考平台_牛客网
很经典了。。。也算得上是一道板子题了

没有过多可以描述的,枚举每一行的合法状态,然后一次枚举上一行,上上一行,要求状态不矛盾。

可以用vector来做一个预处理,然后

因为每一层都是只有满足地图条件并且不会自矛盾才能有非0的dp值,所以每一次除了枚举这一行要将当前状态与地图进行对比外,它的上一行,上上一行都不需要再与地图进行对比了。

最后如果按状态开1<<10位的数组的话,三维吃不消,可以做一个小优化,打表发现合法状态也就六十几个,所以dp数组的后两维只开70也就够了,不过这样的话,dp里面就不再是对应的状态了,而是对应的状态的编号(因为是编号只有六十几个,而不是状态本身);体现在代码中

for(ll i=1;i<=n;++i){
        for(ll q=0;q<vt.size();++q){//枚举当前行所有状态
            ll st=vt[q];
            if((st&mapp[i])!=st) continue;//与地图对比 
            for(ll w=0;w<vt.size();++w){//枚举上一行
                ll st1=vt[w];
                if(st1&st) continue;
         //       if((st1&mapp[i-1])!=st1) continue;//与地图对比 
                for(ll e=0;e<vt.size();++e){
                    ll st2=vt[e];
                    if(st1&st2) continue;
                    if(st&st2) continue;
        //           if((st2&mapp[i-2])!=st2) continue;//与地图对比 
                    dp[i][q][w]=max(dp[i][q][w],num[q]+dp[i-1][w][e]);

(这里就是用q、w来对st1和st2了)
                    ans=max(ans,dp[i][q][w]);
                   }
            }
        }
    } 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m,ans;
ll mapp[110];
char k;
ll dp[110][70][70];//第i行状态为j,第i-1行状态为k的最大士兵数
vector<ll> vt;//存合法状态 
vector<ll> num;
ll calc(ll x){
    ll num=0;
    while(x)
   {
       if(x&1) num++;
        x>>=1;
   }
    return num;
}
int main()
{
	cin>>n>>m;
    ans=0;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			cin>>k;
            mapp[i]*=2;
			if(k=='P') mapp[i]++;
		}
	}
	for(ll i=0;i<(1<<m);++i){
		if(i&(i<<1)) continue;
		if(i&(i<<2)) continue;
//         if(i&(i>>1)) continue;
// 		if(i&(i>>2)) continue;
		vt.push_back(i);//枚举并存放合法状态 
        num.push_back(calc(i));
	}
	for(ll i=1;i<=n;++i){
		for(ll q=0;q<vt.size();++q){//枚举当前行所有状态
            ll st=vt[q];
			if((st&mapp[i])!=st) continue;//与地图对比 
			for(ll w=0;w<vt.size();++w){//枚举上一行
                ll st1=vt[w];
				if(st1&st) continue;
         //       if((st1&mapp[i-1])!=st1) continue;//与地图对比 
				for(ll e=0;e<vt.size();++e){
                    ll st2=vt[e];
					if(st1&st2) continue;
					if(st&st2) continue;
        //           if((st2&mapp[i-2])!=st2) continue;//与地图对比 
					dp[i][q][w]=max(dp[i][q][w],num[q]+dp[i-1][w][e]);
                    ans=max(ans,dp[i][q][w]);
                   }
			}
		}
	} 
	cout<<ans<<endl;
	return 0;
 } 
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值