//给一个n*m的地图。坦克从(0 , 0)開始走
//#表示墙不能走,*表示传送门能够传送到指定地方,能够选择也能够选择不传送
//数字表示该格的矿石数,
//坦克从(0,0)開始走。仅仅能往右和往下走。
//问最多能得到多少矿石
//直接建图,但因为有传送门。须要缩点
//然后用dfs直接搜一条权值最大的路
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
using namespace std ;
const int maxn = 2010 ;
int dfn[maxn] , low[maxn] , vis[maxn] , stack[maxn] ;int ans ;
int head[maxn*maxn] , belong[maxn] ,isstack[maxn] ;
int num , top , nedge , step ;int X[maxn] , Y[maxn] ; int n, m ;
int w[maxn];int a[maxn];int len;int visit[50][50];
int map[maxn][maxn] ;int pos ;
char str[maxn][maxn] ;
int dx[2] = {0,1} ;
int dy[2] = {1,0} ;
vector<int>vec[maxn] ;
struct Edge
{
    int v ;
    int next ;
}edge[maxn*maxn] ;
void addedge(int u , int v)
{
    edge[nedge].v = v ;
    edge[nedge].next = head[u] ;
    head[u] = nedge++ ;
}
void init()
{
    for(int i = 0;i <= n*m;i++)
    vec[i].clear() ;
    memset(head , -1 , sizeof(head)) ;
    memset(w ,0 , sizeof(w)) ;
    memset(dfn , 0 , sizeof(dfn)) ;
    memset(isstack ,0 , sizeof(isstack)) ;
    memset(map , 0 , sizeof(map)) ;
    memset(vis ,0 , sizeof(vis)) ;
    memset(a ,0 , sizeof(a)) ;
    num = top = nedge = step = len = 0 ;
}
void tarjan(int u)
{
    stack[++top] = u ;
    isstack[u] = 1 ;
    low[u] = dfn[u] = ++step ;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].v ;
        if(!dfn[v])
        {
            tarjan(v) ;
            low[u]  = min(low[u] , low[v]) ;
        }
        else if(isstack[v])
        low[u] = min(low[u] , dfn[v]) ;
    }
    if(low[u] == dfn[u])
    {
        num++ ;
        int v = -1 ;
        while(u != v)
        {
            v = stack[top--] ;
            isstack[v] = 0 ;
            belong[v] = num ;
            w[num] += a[v];
            if(v==0)pos = num ;
        }
    }
}
void build_tree()
{
    for(int i = 0;i <= n*m;i++)
      for(int j = head[i] ; j != -1 ; j =edge[j].next)
      {
          int u = belong[i] ;
          int v = belong[edge[j].v] ;
          if(u == v)continue ;
          vec[u].push_back(v) ;
          vis[v] = 1 ;
      }
}
int dfs(int u)
{
    int ma = 0 ;
    for(int i = 0;i < vec[u].size() ;i++)
    {
        int v = vec[u][i] ;
        ma = max(ma , dfs(v)) ;
    }
    ans = max(ans , ma+w[u]) ;
    return ma + w[u] ;
}
int main()
{
    //freopen("in.txt" , "r" , stdin) ;
    int t ;
    scanf("%d" , &t) ;
    while(t--)
    {
        scanf("%d%d" , &n , &m) ;
        init() ;
        ans = 0 ;
        for(int i = 0;i < n;i++)
        scanf("%s" ,str[i]) ;
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < m;j++)
             if(str[i][j] != '#')
             {
                if(str[i][j] == '*')
                {
                   X[++len] = i ;
                   Y[len] = j ;
                   a[i*m+j] = 0 ;
                }
                else
                {
                    a[i*m + j] = str[i][j] - '0' ;
                    ans = max(ans , a[i*m+j]) ;
                }
                for(int k = 0 ;k < 2;k++)
                {
                    int nx = i + dx[k] ;
                    int ny = j + dy[k] ;
                    if((nx >= n || ny >= m))
                    addedge(i*m + j , n*m) ;
                    else if(str[nx][ny] != '#')
                    addedge(i*m + j , nx*m + ny) ;
                }
             }
        }
        for(int i = 1;i <= len ;i++)
        {
            int u , v ;
            scanf("%d%d" , &u , &v) ;
            addedge(X[i]*m+ Y[i] , u*m+v) ;
        }
        pos = 0 ;
        for(int i = 0;i <= n*m;i++)
        if(head[i] != -1 && !dfn[i])
        tarjan(i) ;
        if(!pos)
        {
            cout<<ans<<endl;
            continue ;
        }
        build_tree() ;
        dfs(pos) ;
        printf("%d\n" ,ans) ;
    }
}