状态压缩dp求调
查看原帖
状态压缩dp求调
210719
Violet___Evergarden楼主2021/9/20 10:17
#include <iostream>
#include <climits>
using namespace std;
const int kMaxN=101;
const int kMaxM=11;
int dp[kMaxN][1<<10][1<<10];//dp[i][j][k]为第i行,这一行为j,上一行为k时能放多少个
int n,m;
int mp[kMaxN][kMaxM],ans;
int zk[kMaxN];
int cnt;
struct CAN
{
  int zt,num;
}can[1<<10];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
  zk[i]=0;
  for(int j=1;j<=m;j++)
  {
    char a;
    cin>>a;
    mp[i][j]=(a=='P'?1:0);//放部队代表1,不放代表0
    zk[i]=(zk[i]<<1)+mp[i][j];//算每一行的平原的状态
  }
}
for(int i=1;i<=(1<<m)-1;i++)
{
  if(i&(i<<1))continue;//判断这种放法是否不行(即左边或右边2个格子放了)
  if(i&(i<<2))continue;
  if(i&(i>>1))continue;
  if(i&(1>>2))continue;
  can[++cnt].zt=i;
  int z=i;
  while(z)//算出这种情况放了几个
  {
    if(z&1)
    {
      can[cnt].num++;
    }
    z>>=1;
  }
}
for(int i=1;i<=cnt;i++)//特殊处理第一行
{
  if((can[i].zt&zk[1])!=can[i].zt)continue;//判断山地有没有放
  dp[1][i][0]=can[cnt].num;
}
for(int i=1;i<=cnt;i++)//特殊处理第二行
{
  if((can[i].zt&zk[1])!=can[i].zt)continue;
  for(int j=1;j<=cnt;j++)
  {
    if((can[j].zt&zk[2])!=can[j].zt)continue;
    if((can[i].zt&can[j].zt))continue;
    dp[2][j][i]=can[i].num+can[j].num;
  }
}
for(int i=3;i<=n;i++)//处理3~n行
{
  for(int j=1;j<=cnt;j++)//枚举上上行的状态
  {
    if((can[j].zt&zk[i-2])!=can[j].zt)continue;
    for(int k=1;k<=cnt;k++)//枚举上行的转台
    {
      if((can[k].zt&zk[i-1])!=can[k].zt)continue;
      if((can[j].zt&can[k].zt))continue;
      for(int l=1;l<=cnt;l++)//枚举这一行的状态
      {
        if((can[l].zt&can[i].zt))continue;
        if((can[l].zt&can[j].zt))continue;
        if((can[l].zt&zk[i])!=can[l].zt)continue;;
        dp[i][l][k]=max(dp[i][l][k],dp[i-1][k][j]+can[l].num);
        ans=max(ans,dp[i][l][k]);
      }
    }
  }
}
cout<<ans;
return 0;
}
2021/9/20 10:17
加载中...