乍看这题,差不多理清要枚举上层和上上层……
然而……,1000^3能过?!
然后发现许多状态预处理时就能删掉……统共合理的(没有相邻1)的情况不过100+
于是预处理出前两层的答案
转移时三层枚举
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 125 + 50;
int dp[MAXN][MAXN][MAXN],num[MAXN];
int vis[11];
int digit[MAXN],tot,n,m;
void init()
{
for(int i = 1;i <= 4048;i ++)
{
int w = 0,cnt = 0;
bool flag = true;
memset(vis,0,sizeof(vis));
while((1 << w) <= i)
{
if(i & (1 << w))
{
vis[w] = true;
cnt ++;
if(vis[w - 1] || vis[w - 2])
{
flag = false;
break;
}
}
w ++;
}
if(!flag)continue;
digit[++ tot] = i;
num[tot] = cnt;
}
}
char s[1001];
int mp[1001],ans;
int main()
{
init();
memset(dp,-1,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
{
scanf("%s",s);
for(int j = 0;j < m;j ++)
{
if(s[j] == 'H')
{
mp[i] += (1 << j);
}
}
}
for(int i = 1;i <= tot && digit[i] < (1 << m);i ++)
{
for(int j = 1;j <= tot && digit[j] < (1 << m);j ++)
{
int tmp1 = digit[i];
int tmp2 = digit[j];
if((!(tmp1 & tmp2)) && (!(tmp1 & mp[2])) && (!(tmp2 & mp[1])))
{
dp[2][i][j] = num[i] + num[j];
ans = max(ans,dp[2][i][j]);
}
}
}
for(int k = 3;k <= n;k ++)
{
for(int i = 0;i <= tot && digit[i] < (1 << m);i ++)
{
if(digit[i] & mp[k - 1])continue;
for(int j = 0;j <= tot && digit[j] < (1 << m);j ++)
{
if(digit[j] & mp[k - 2])continue;
if(dp[k - 1][i][j] == -1)continue;
//dp[k][0][i] = max(dp[k][0][i],dp[k - 1][i][j]);
for(int t = 0;t <= tot && digit[t] < (1 << m);t ++)
{
if(!(digit[t] & mp[k]) && (!(digit[t] & digit[i])) && (!(digit[t] & digit[j])))
{
dp[k][t][i] = max(dp[k][t][i],num[t] + dp[k - 1][i][j]);
ans = max(ans,dp[k][t][i]);
}
}
}
}
}
printf("%d",ans);
return 0;
}
还有一份wwq大佬的代码,预处理略微不同,判断是否有相邻1时更机智
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=100+5;
int f[MAXN][100][100],mp[MAXN],sav[100],num[100];
char ch[12];
int n,m,cnt;
bool check(int x)
{
if((x&(x<<1))||(x&(x<<2))) return 0;
return 1;
}
void read(int& x)
{
char c;
x=0;
for(c=getchar();c!='P'&&c!='H';c=getchar());
for(int i=0;c=='P'||c=='H';c=getchar(),++i)
if(c=='H')
x|=(1<<i);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
read(mp[i]);
for(int i=0;i<1<<m;++i)
if(check(i))
{
sav[++cnt]=i;
for(int j=0;j<m;++j)
if(i&(1<<j))
++num[cnt];
}
for(int i=1;i<=cnt;++i)
if(!(sav[i]&mp[1]))
f[1][i][1]=num[i];
for(int i=2;i<=n;++i)
for(int j=1;j<=cnt;++j)
{
if(sav[j]&mp[i]) continue;
for(int k=1;k<=cnt;++k)
{
if((sav[k]&mp[i-1])||(sav[j]&sav[k]))
continue;
for(int w=1;w<=cnt;++w)
{
if((sav[w]&mp[i-2])||(sav[w]&sav[j])||(sav[w]&sav[k]))
continue;
f[i][j][k]=max(f[i][j][k],f[i-1][k][w]+num[j]);
}
}
}
int ans=0;
for(int i=1;i<=cnt;++i)
{
if(mp[n]&sav[i]) continue;
for(int j=1;j<=cnt;++j)
{
if(!(mp[n-1]&sav[j])&&!(sav[i]&sav[j]))
ans=max(ans,f[n][i][j]);
}
}
printf("%d",ans);
return 0;
}