题目如下:
Input:
4
2 3
.*.
***
2 3
.*.
**.
4 5
.***.
*****
*****
*.*.*
5 7
..*.*..
.*****.
*******
.*****.
..*.*..
Output:
5
3
23
34
思路:
看出来这是DP就好解决了
首先观察到当一个位置为 * 时必然圣诞树数量至少为一,想让此点向下形成圣诞树,其下方、左下方、右下方都必须也是 *,只要这三个位置有一个不是 * ,那么就不会继续向下生成圣诞树了。也就是说:
dp[i][j]=min(dp[i+1][j-1],min(dp[i+1][j],dp[i+1][j+1]))+1;
//要+1是因为要加上自身这一个*行程的圣诞树
由此,我们倒着分析这张图,一层层去向上推进dp[i][j]的数值
以最后一个样例为例,可以写出dp图为:
总数把这些加起来即可!
分析结束,开始实操:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
char mp[600][600];
int dp[600][600];
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>mp[i][j];
if(mp[i][j]=='*')
{
dp[i][j]++;//先把*标记出来
}
}
}
for(int i=n-1;i>=1;i--)//从图的右下角开始
{
for(int j=m-1;j>=2;j--)//图的边线位置的*必然只能产生一种圣诞树(也就是他本身,因为他没办法向下生成圣诞树)
{
if(mp[i][j]=='.')
dp[i][j]=0;
else
dp[i][j]=min(dp[i+1][j-1],min(dp[i+1][j],dp[i+1][j+1]))+1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ans+=dp[i][j];//加起来
//cout<<dp[i][j]<<' ';
}
//cout<<endl;
}
cout<<ans<<endl;
memset(dp,0,sizeof(dp));//不要忘记清零
}
return 0;
}
写了这么久代码,每天找水题找找自信。。。