题目大意:
题目链接:
POJ:http://poj.org/problem?id=1185
洛谷:https://www.luogu.org/problemnew/show/P2704
在一个 n × m n\times m n×m的网格中,有些格子可以选择,任意两个选择的点不可以在同一直线的距离小于3。求最大的选择方案。
思路:
m
≤
10
m\leq 10
m≤10,可以考虑状压
d
p
dp
dp。
由于对于一个点选择或者不选会影响到下面两行的选择,所以我们可以设
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示第
i
i
i行,这一行和上一行的放置方案为
j
j
j和
k
k
k的方案数。设上上行的状态为
l
l
l,则有
f
[
i
]
[
j
]
[
k
]
=
m
a
x
(
f
[
i
]
[
j
]
[
k
]
,
f
[
i
−
1
]
[
k
]
[
l
]
+
s
u
m
[
j
]
)
f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+sum[j])
f[i][j][k]=max(f[i][j][k],f[i−1][k][l]+sum[j])
其中
s
u
m
[
j
]
sum[j]
sum[j]表示状态为
j
j
j放置的个数(即状态为
j
j
j中数字1的个数)
但是这样的时间复杂度为
O
(
n
×
(
2
m
)
3
)
O(n\times (2^m)^3)
O(n×(2m)3),空间复杂度为
O
(
n
m
2
)
O(nm^2)
O(nm2),TLE+MLE两开花(TM两开花XD)。
我们会发现枚举时有太多状态是不成立的。也就是说这个状态中就有两个1之间的距离小于3,。所以我们可以预处理出所有的合法的状态(即任意两个1之间的距离至少为3),然后直接枚举这些状态(顺便预处理出
s
u
m
sum
sum数组)。
这样可以省去超级多的无用状态,大大减少时间复杂度。
然后我们为了减少空间,可以设
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示第
i
i
i行,这一行的状态是第j个合法的状态,上一行的状态是第k个合法的状态
时的最多放置方案数。方程没有怎么变。
这样就可以过掉本题了。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N=110;
const int MAXN=(1<<10);
int n,m,maxn,map[N],q[MAXN],sum[MAXN],tot,ans;
char ch;
bool check(int x) //判断这个状态是否合法
{
int cnt=0,sum;
while (x)
{
if ((x&1)&&cnt) return 0;
if (x&1) cnt=3;
if (cnt) cnt--;
x>>=1;
}
return 1;
}
int count(int x) //计算这个撞他中有几个1(您强可以使用lowbit)
{
int cnt=0;
while (x)
{
cnt+=(x&1);
x>>=1;
}
return cnt;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
cin>>ch;
map[i]=(map[i]<<1)+(ch=='H'); //压缩这一行的那些位置可以放
}
maxn=(1<<m);
for (int S=0;S<maxn;S++) //预处理
if (check(S))
{
q[++tot]=S;
sum[tot]=count(S);
}
int f[N][tot+1][tot+1]; //压缩空间复杂度
memset(f,0,sizeof(f));
for (int i=1;i<=n;i++)
for (int j=1;j<=tot;j++)
if (i==1||!(q[j]&map[i-2]))
for (int k=1;k<=tot;k++)
if (!(q[k]&map[i-1])&&!(q[j]&q[k]))
for (int l=1;l<=tot;l++)
if (!(q[l]&map[i])&&!(q[j]&q[l])&&!(q[k]&q[l]))
f[i][l][k]=max(f[i][l][k],f[i-1][k][j]+sum[l]);
for (int i=1;i<=tot;i++)
for (int j=1;j<=tot;j++)
ans=max(ans,f[n][i][j]);
printf("%d",ans);
return 0;
}