Luogu P2704 [NOI2001]炮兵阵地
作者:互联网
还是状压dp...
因为int开成bool了de了好久,最后还是wjh帮忙看出来的qaq
f[i][k][j]代表第i行,状态为j,上一行状态为k,上上行的状态为kk
四重循环,保证j,k、j,kk、k,kk不冲突的前提下,有:
f[i][k][j] = max(f[i][kk][k] + sum[j])
因为状态太多了存不下,所以只要把可行的状态记录下来,也就是说离散化一下w
据说还可以用滚动数组,只记录两行的(f[i%2][j][k])不过空间反正足够了
前两行初始化要稍微注意下。
一点以后可能有用的优化:
1.这个题“只能放在平原上,不能放在山地上”,我原来是写完全包含 (g[j]|a[i]) == a[i]
后来看题解a[i]存的是山地的位置,也就是 !(
g[j]&a[i])
2.这个题是横着比较短而竖着比较长而爆空间的…
如果遇到竖着短横着长的情况,不妨把它旋转一下。这样枚举状态的循环就会变得短一些!
代码如下
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MogeKo qwq using namespace std; char s[15]; int n,m,ans,cnt; int a[1<<11],sum[70],f[105][70][70],g[70]; int main() { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) { scanf("%s",s); for(int j = 0; j < m; j++) a[i] = (a[i] << 1)|(s[j] == 'H'); } for(int i = 0; i < (1<<m); i++) { if(i&(i<<2)||i&(i<<1)||i&(i>>1)||i&(i>>2)) continue; g[++cnt] = i; for(int j = 0; i>>j; j++) sum[cnt] += (i>>j)&1; if(g[cnt]&a[1]) continue; f[1][0][cnt] = sum[cnt]; } for(int i = 1; i <= cnt; i++) for(int j = 1; j <= cnt; j++) { if(g[j] & a[2]) continue; if(g[j] & g[i]) continue; f[2][i][j] = max(f[2][i][j],f[1][0][i] + sum[j]); } for(int i = 3; i <= n; i++) for(int j = 1; j <= cnt; j++) { if(g[j]&a[i]) continue; for(int k = 1; k <= cnt; k++) for(int kk = 1; kk <= cnt; kk++) { if(g[j]&g[k] || g[j]&g[kk] || g[k]&g[kk]) continue; f[i][k][j] = max(f[i][k][j],f[i-1][kk][k]+sum[j]); ans = max(ans,f[i][k][j]); } } printf("%d\n",ans); return 0; }View Code
标签:状态,cnt,int,Luogu,sum,kk,NOI2001,P2704,include 来源: https://www.cnblogs.com/mogeko/p/11713203.html