求条
j27eGU
2025-06-28 22:58:31
2025-06-29 9:05:38
r
#include<bits/stdc++.h>
using namespace std;
int qk[110],dp[110][(1<<10)];
bool can[110];
int res(int n)
{
int ans=0;
while(n)
{
ans+=(n%2);
n/=2;
}
return ans;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char c;
cin>>c;
qk[i]=(qk[i]<<1)+(c=='H');
}
for(int i=0;i<(1<<m);i++)
if(!((i<<1)&i)&&!((i<<2)&i)&&!((i>>1)&i)&&!((i>>2)&i))
{
can[i]=1;
if((i&qk[1])==0)
{
dp[1][i]=res(i);
}
}
if(n==1)
{
int ans=0;
for(int i=0;i<(1<<m);i++)ans=max(ans,dp[1][i]);
cout<<ans;
return 0;
}
for(int qk1=0;qk1<(1<<m);qk1++)
if(dp[1][qk1])
for(int qk2=0;qk2<(1<<m);qk2++)
if(can[qk2]&&(qk1&qk2)==0&&(qk2&qk[2])==0)
{
dp[2][qk2]=res(qk2)+dp[1][qk1];
}
if(n==2)
{
int ans=0;
for(int i=0;i<(1<<m);i++)ans=max(ans,dp[2][i]);
cout<<ans;
return 0;
}
for(int i=3;i<=n;i++)
for(int qk1=0;qk1<(1<<m);qk1++)
if(can[qk1]&&(qk1&qk[i-2])==0)
for(int qk2=0;qk2<(1<<m);qk2++)
if(can[qk2]&&(qk2&qk[i-1])==0&&(qk1&qk2)==0)
for(int qk3=0;qk3<(1<<m);qk3++)
if(can[qk3]&&(qk3&qk[i])==0&&(qk1&qk3)==0&&(qk2&qk3)==0)
{
dp[i][qk3]=dp[i-1][qk2]+res(qk3);
}
int ans=0;
for(int i=0;i<(1<<m);i++)
ans=max(ans,dp[n][i]);
cout<<ans;
return 0;
}
共 2 条回复
状压dp
qk是用来存储山地和平原情况的,山地为1,平原为0
can是判断在当前行内炮兵的排列是否合法,即1个炮兵的左边两格和右边两格以内是没有炮兵的
dp数组第一个是行,第二个是这个当前行的炮兵情况,dp[i][j]存储的是在第i行内,炮兵排列情况为j时最多能放几个炮兵
最后的一大坨for循环时递推计算dp
看不懂qwq