Description
有一个矩阵,上面的点分别是山地和平原,如果某个在上面放炮车,那么相邻的十字形就不能放了
山地上不能放炮车,问最多可以放几辆炮车
(n le 1000 mle10)
Solution
这个题首先我们要状压
定义 (f_{i,j,k}) 为 第 (i) 行 状态为 (j) 时,第 (i-1) 行状态为 (k) 时最大放炮车数
枚举状态是不是合法然后转移即可
如果时间卡到(200ms)
我们需要先看一下哪些点符合并且把它们放到一个数组里面,然后直接在那个里找
Code
#include<bits/stdc++.h>
using namespace std;
#define reg register
#define int short int
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=110,M=1030;
int f[2][M][M],n,m,p[N],b[1030];
char s[N][11];
int pos[M],cnt;
inline int max(int x,int y){return x<y?y:x;}
signed main()
{
for(reg int i=1;i<=1030;++i) b[i]=b[i>>1]+(i&1);
n=read(); m=read();
for(reg int i=1;i<=n;++i)
{
scanf("%s",s[i]+1);
for(reg int j=1;j<=m;++j)
{
if(s[i][j]=='H') p[i]=p[i]|(1<<(j-1));
}
}
for(int i=0;i<(1<<m);++i)
{
if(i&(i<<1)||i&(i<<2)) continue;
pos[++cnt]=i;
}
for(reg int i=1;i<=n;++i)
{
for(int j=1;j<=cnt;++j)
{
if(pos[j]&p[i]) continue;
for(int k=1;k<=cnt;++k)
{
if(pos[k]&p[i-1]||pos[j]&pos[k]) continue;
for(int l=1;l<=cnt;++l)
{
if(pos[l]&pos[k]||pos[l]&pos[j]||pos[l]&p[max(i-2,0)]) continue;
f[i&1][j][k]=max(f[i&1][j][k],f[(i-1)&1][k][l]+b[pos[j]]);
}
}
}
}
int s=1<<m,ans=0;
for(int i=1;i<=cnt;++i)
{
for(int j=1;j<=cnt;++j) ans=max(ans,f[n&1][i][j]);
}
printf("%d
",ans);
return 0;
}
}
signed main(){return yspm::main();}
Review
如果 (T) ,先想做法有没有什么可以剪枝优化的,然后再卡常