Codeforces Round #689 (Div. 2, based on Zed Code Competition)-B. Find the Spruce(DFS+記憶化搜尋)

獨一無二的VV發表於2020-12-12

題目連結

Codeforces Round #689 (Div. 2, based on Zed Code Competition)-B. Find the Spruce


Description

  • Holidays are coming up really soon. Rick realized that it’s time to think about buying a traditional spruce tree. But Rick doesn’t want real trees to get hurt so he decided to find some in an n×m matrix consisting of “*” and “.”.
    To find every spruce first let’s define what a spruce in the matrix is. A set of matrix cells is called a spruce of height k with origin at point (x,y) if:
    All cells in the set contain an "".
    For each 1≤i≤k all cells with the row number x+i−1 and columns in range [y−i+1,y+i−1] must be a part of the set. All other cells cannot belong to the set.

Input

  • Each test contains one or more test cases. The first line contains the number of test cases t (1≤t≤10).
    The first line of each test case contains two integers n and m (1≤n,m≤500) — matrix size.
    Next n lines of each test case contain m characters ci,j — matrix contents. It is guaranteed that ci,j is either a “.” or an “*”.
    It is guaranteed that the sum of n⋅m over all test cases does not exceed 500^2 (∑n⋅m≤500^2).

Output

  • For each test case, print single integer — the total number of spruces in the matrix.

輸入

4
2 3
.*.
***
2 3
.*.
**.
4 5
.***.
*****
*****
*.*.*
5 7
..*.*..
.*****.
*******
.*****.
..*.*..

輸出

5
3
23
34

思路

  • 思路:實際上可以把題目意思轉化為所有以"*"的點為樹的頂點所能構成的雲杉樹的深度的和,例如樣例一,第一排中間的"*“為頂點構成的樹的深度為2,而第二排中間的”*"為頂點構成的樹的深度為1所以ans=2+1+1+1=5
  • 方法:對每一個“*”用 dfs搜尋 樹的深度,因為要保證樹完整所以dfs返回值為最小的樹的深度+1。
  • 注意:要用記憶化搜尋(二維陣列dp儲存dfs的值,避免重複搜尋造成時間浪費),不然會超時。

AC程式碼

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
string s[600];
int dp[600][600];//儲存dfs的值
int sum=0,n,m;
int dfs(int x,int y){//dfs求樹的深度
    if(dp[x][y]) return dp[x][y];//如果搜尋過就返回dp
    int flag=0;//判斷是否能繼續往下
    if(x+1<n&&y-1>=0&&x+1>=0&&y+1<m){
        if((s[x+1][y]=='*')&&(s[x+1][y-1]=='*')&&(s[x+1][y+1]=='*')){
            flag=1;
        }
    }
    if(flag) return dp[x][y]=1+min(min(dfs(x+1,y),dfs(x+1,y-1)),dfs(x+1,y+1));//因為要保證樹完整所以要求最小的樹的深度
    else return dp[x][y]=1;//深度為1即一個點
}
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(dp,0,sizeof(dp));
        cin>>n>>m;
        sum=0;
        for(int i=0;i<n;i++){
            cin>>s[i];
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(s[i][j]=='*'){
                    sum+=dfs(i,j);
                }
            }
        }
        cout<<sum<<endl;
    }
}
  • 一開始沒用記憶化搜尋結果Time limit exceeded…

相關文章