题面
题意
给出一个矩阵,矩阵中的点是白点或黑点,现在要你放入3个’L’形,要求‘L’形都不经过黑点,问一共有几种方案。
做法
首先暴力枚举这三个‘L’左下角的点在哪一行,然后一列一列更新状态,对于每个L有三种状态:
0:表示还未放。
1:表示正在放(L横着的这段)。
2:已经放好了。
然后用dp[列数][状态(3*3*3)]。
需要注意的是,L横着的这段至少有两个,因此在更新的时候要特判一下,还有在从0->1时,需要乘上竖着的‘L’放的种类数,这个数量与地图和另外两个’L’的状态都有关系,以及几个‘L’在同一行时的情况。
此题状态转移时,特判比较多,详见代码。
代码
#include <bits/stdc++.h>
#define ll long long
#define N 35
using namespace std;
class ThreeLLogo
{
public:
long long countWays( vector <string> grid );
};
ll up[N][N],pos[5],ans,dp[N][30],a,b,c,na,nb,nc,res,tmp;
bool mm[N][N];
inline void get(ll u)
{
a=u/9;
b=u%9/3;
c=u%3;
}
inline ll fget(ll u,ll v,ll w)
{
return u*9+v*3+w;
}
//0 未放
//1 在放
//2 放完
long long ThreeLLogo::countWays(vector <string> grid)
{
ll i,j,k,m=grid.size(),n=grid[0].size();
memset(mm,0,sizeof(mm));
memset(up,0,sizeof(up));
ans=0;
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
if(grid[i][j]=='#')
{
mm[i+1][j+1]=1;
up[i+1][j+1]=-1;
}
else if(!i) up[i+1][j+1]=0;
else up[i+1][j+1]=up[i][j+1]+1;
}
}
for(i=1;i<=m+1;i++) mm[i][n+1]=1;
for(i=1;i<=n;i++) mm[m+1][i]=1;
for(pos[1]=1;pos[1]<=m;pos[1]++)
{
for(pos[2]=pos[1];pos[2]<=m;pos[2]++)
{
for(pos[3]=pos[2];pos[3]<=m;pos[3]++)
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(i=0;i<n;i++)
{
for(j=0;j<27;j++)
{
if(!dp[i][j]) continue;
get(j);
for(k=0;k<8;k++)
{
na=a+k/4;
nb=b+k/2%2;
nc=c+k%2;
if(na>2||nb>2||nc>2) continue;
if((na==1 || a==1) && mm[pos[1]][i+1]) continue;
if((nb==1 || b==1) && mm[pos[2]][i+1]) continue;
if((nc==1 || c==1) && mm[pos[3]][i+1]) continue;
if(!a && na==1 && mm[pos[1]][i+2]) continue;
if(!b && nb==1 && mm[pos[2]][i+2]) continue;
if(!c && nc==1 && mm[pos[3]][i+2]) continue;
if(pos[1]==pos[2] && na<nb) continue;
if(pos[2]==pos[3] && nb<nc) continue;
res=1;
if(!a && na==1) res*=up[pos[1]][i+1];
if(!b && nb==1)
{
if(na==1 || a==1) res*=min(up[pos[2]][i+1],pos[2]-pos[1]-1);
else res*=up[pos[2]][i+1];
}
res=max(res,0ll);
if(!c && nc==1)
{
tmp=up[pos[3]][i+1];
if(na==1 || a==1) tmp=min(tmp,pos[3]-pos[1]-1);
if(nb==1 || b==1) tmp=min(tmp,pos[3]-pos[2]-1);
res*=tmp;
}
res=max(res,0ll);
dp[i+1][fget(na,nb,nc)]+=dp[i][j]*res;
}
}
}
ans+=dp[n][26];
}
}
}
return ans;
}