第一次状压的话建议先做:P1896 [SCOI2005] 互不侵犯
题目要点如下:
-
每个炮兵会打到上下两行,左右各两格的队友
-
有地形限制,山上不能放炮兵
考虑状态定义:
第一维:由于会影响上下两行,所以要以两行为单位来规划。
第二维:要枚举与当前双行状态相容的上面的(也就是第i-2和i-1行的)双行状态,所以要把当前行的状态记录下来~~(这不废话~~
所以状态表示:
f[i][j]表示(i与i+1行)状态为j时,能发下的最多炮兵个数
那么方程也就很简单了,只要找到与最大的与当前状态相容的f[i-2][k],加上当前状态的炮兵个数就行了:
f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i − 2 ] [ k ] ) + n u m [ j ] f[i][j]=max(f[i][j],f[i-2][k])+num[j] f[i][j]=max(f[i][j],f[i−2][k])+num[j]
预处理:
-
穷举出单行合法状态
-
用单行合法状态穷举出双行合法状态
-
处理出双行的合法状态的后继双行合法状态
-
(处理出双行合法状态的后继单行合法状态)
dp过程:
-
将第一行和第二行的状态初始化(与地形不相容的continue)
-
从第三行开始dp,枚举行
-
枚举当前行的状态(与地形不相容的continue)
-
枚举与当前行相容的状态(作为i-2与i-1的状态)
-
转移
由状态定义可知,max(f[n-1][i])即为所求
完
你是不是忘了n%2==1的情况了…
所以如果是奇数行的话,dp到第n-2和n-1行就停,最后单独dp一行
一些细枝末节的地方可以看看代码注释
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
using namespace std;
int n,m;
char a[120][10];
int num1[70];int cnt1;
int num2[2200];int cnt2;
int lf[120];
vector<int> st1;
vector<pii> st2;
vector<int> vt[2200];
vector<int> vt1[70];
ll f[120][