dp[1][2][3][4]
//位置
//方向
//可转向次数
//本题需要结合dfs+记忆化搜索+动态规划来解题
//对于当前坐标(i,j),其下一步有两个转移方向,分别是向下(i+1,j)和向右(i,j+1)
//故从(i,j)到达(N,M)的方案数等于从(i+1,j)到(N,M)和从(i,j+1)到(N,M)的方案数之和
//由于最多转向K次,每次转移状态时需要记录当前方向和下一步转移的方向,以及已经转向的次数
//且每次回溯时都要恢复转向次数k,时间复杂度很高,因此使用记忆化数组保存中间结果
//故使用四维记忆化数组进行记录,每转移一次都要传入当前坐标、当前方向、已转移次数等参量
#include <bits/stdc++.h>
using namespace std;
char matrix[110][110];//迷宫矩阵
int N,M,K;
int dp[105][105][2][7];//记忆化数组
//dp[i][j][0][k]表示从(i,j)开始,方向向右,共改变了k次方向,能到达终点的方案数
//dp[i][j][1][k]表示从(i,j)开始,方向向下,共改变了k次方向,能到达终点的方案数
bool ok(int i,int j)//判断是否是可通行的点
{
//if(i>N||j>M)return false;
//这里可以优化,只要不是点就返回false
if(matrix[i][j]=='.')return true;
else return false;
}
int dfs(int row,int col,int tag,int k)//从(row,col)开始进行dfs,当前方向为tag,总共改变了k次方向
{
int cnt=0;//记录总方案数
if(!ok(row,col))return 0;//该点不可通行,直接返回0
if(row==N&&col==M)return 1;//到达终点,直接返回1,表示这是一种方案最终条件
if(dp[row][col][tag][k])return dp[row][col][tag][k];
//已经搜索过该点,直接返回记忆化数组的值
//一开始是的值都是0,所以不会进行
if(k<K)//转向的次数没有超过K次
{//看来碰到石头并不是碰到石头再转向
cnt=cnt+dfs(row+1,col,1,tag==1?k:k+1);//向下
//这一步是向下走,tag为1表示原来向下,所以不转向,所以k不变化
//反之若tag=0说明表示往右走则k++
cnt=cnt+dfs(row,col+1,0,tag==0?k:k+1);//向右
}
else if(k==K)//转向次数已经达到K次
{
if(tag==0)//原来向右
{
cnt=cnt+dfs(row,col+1,tag,k);//继续向右
}
else if(tag==1)//原来向下
{
cnt=cnt+dfs(row+1,col,tag,k);//继续向下
}
}
dp[row][col][tag][k]=cnt;//当前值为从当前点出发的所有值
//记忆化,将从(row,col)到(N,M)的总方案数保存起来
//最后这个cnt直接将结果保存下来了
return cnt;//返回从(row,col)到(N,M)的方案数
}
int main()
{
int ans=0;
cin>>N>>M>>K;
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++)
{
for(int j=1;j<=M;j++)
{
cin>>matrix[i][j];
}
} //初始化数组并且
//此处要注意一点,起点(1,1)处是没有当前方向的,需要前进一步才有方向
if(ok(1,2))ans=ans+dfs(1,2,0,0);//从(1,2)开始
if(ok(2,1))ans=ans+dfs(2,1,1,0);//从(2,1)开始
cout<<ans<<endl;
return 0;
}