[NOI2001]炮兵阵地(双行状态压缩dp)

src: https://www.luogu.org/problemnew/show/P2704

因为这道题他会向四周延伸2格,所以初始化的时候要左移1位和左移2位判断。而存状态的时候需要把当前行和上一行一起存了。再扫描上上行。

dp[i][state1][state2]表示第i-1行 state1状态,然后第i行state2状态,然后滚动数组优化后i只用存2个  (状态开k大小,但并不是所有状态都会用到~~~只是用下标存着自己想要的!!!)

为什么要存两行状态呢?试想,如果只存当前行第i行状态state即dp[i][state],那只能满足当前行与上一行不冲突,那么让dp[i][]加上上一行dp[i-1][可行state]时,会发现dp[i-1][可行state]中有部分i-2行的状态会与第i行冲突,,,这就是如果不加i-1行状态就产生后效性(吗),,,然后就是加个上一行的state处理一下~~~

【状态转移方程】dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); num[t]为t状态中1的个数 

【DP边界条件】dp[1][1][i] =num[i] 状态i能够满足第一行的硬件条件,,,为什么state1要用1表示呢?因为state[1]是000.所以不会和第2行产生冲突!!!

ac代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include <cstdlib>
#include<malloc.h>
#include<algorithm>
#include<functional>
#include<utility>
#include<cmath>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<set>
#include<queue>
#include<list>
//#include<bits/stdc++.h>
using namespace std;
int Max(int a, int b) { return a > b ? a : b; }
int Min(int a, int b) { return a > b ? b : a; }
#define FOR(i,a,b) for(int i=a;i<=b;i++)
typedef long long LL;
typedef unsigned long long ull;
const double INF = 99999999999.0;
const double eps = 1e-6;
int n,m,dp[105][70][70],state[70],pao[70],cur[105],nlegal,ans,tot;
string s;
void init()
{
    nlegal=ans=0;
    tot=(1<<m)-1;//哇,要注意优先级啊!!!
    //cout<<"tot "<<tot<<endl;//
    memset(dp,-1,sizeof(dp));
    memset(pao,0,sizeof(pao));
    memset(cur,0,sizeof(cur));
    for(int i=0;i<=tot;i++){
        if((i<<1)&i)continue;
        if((i<<2)&i)continue;
        state[++nlegal]=i;
        int tmp=i;
        while(tmp){
            pao[nlegal]+=tmp%2;
            tmp/=2;
        }
    }
}

int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n>>m;
    init();
    //cout<<nlegal<<endl;//
    //FOR(i,1,nlegal)cout<<state[i]<<' ';cout<<endl;//
    for(int i=1;i<=n;i++){
        cin>>s;
        FOR(j,1,m){
            if(s[j-1]=='H'){
                cur[i]+=1<<(m-j);
            }
        }
    }
    //cout<<"cur1 "<<cur[1]<<" cur2:"<<cur[2]<<endl;//
    for(int i=1;i<=nlegal;i++){
        if(state[i]&cur[1])continue;
        //cout<<"i kexing:"<<i<<' '<<pao[i]<<endl;//
        dp[1][1][i]=pao[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=nlegal;j++){
            if(state[j]&cur[i])continue;
            for(int k=1;k<=nlegal;k++){
                if(state[j]&state[k])continue;
                for(int t=1;t<=nlegal;t++){
                    if(state[t]&state[j])continue;
                    if(state[t]&state[k])continue;
                    //if(i==2)cout<<"state i:"<<state[j]<<"   state i-1:"<<state[k]<<"  state i-2:"<<state[t]<<endl;//

                    dp[i][k][j]=max(dp[i][k][j],dp[i-1][t][k]+pao[j]);
                }
            }
        }
    }
    //FOR(j,1,nlegal){FOR(i,1,nlegal)cout<<dp[n][i][j]<<' ';cout<<endl;}//
    FOR(t,1,n)FOR(i,1,nlegal)FOR(j,1,nlegal)ans=max(ans,dp[t][i][j]);
    //因为可能第n行取得都不合适,dp[n][][]就没处理,所以我们FOR(t,1,n)
    cout<<ans<<endl;
    return 0;
}

 

posted @ 2018-04-06 16:30  WindFreedom  阅读(242)  评论(0)    收藏  举报