[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; }

浙公网安备 33010602011771号