/* 题意:给定一个矩阵,西南角为起点,每个单元都有一定价值的金矿(#表示岩石,不可达,*表示时空门,可以到达指定单元) 现在要求得最多可以获得多大利益 题解:强联通分量,最长路;如果没有时空门,就是纯粹的有向无环图的最长路了,现在出现时空门了,只要求强联通分量进行 缩点,对缩点后的图建立有向无环图,然后求最长路就ok了 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<climits> #include<queue> #include<vector> using namespace std; const int MAXV=49*49; int n,m; int value[MAXV]; char graph[41][41]; struct spfa// spfa求最长路 { static const int INF =-(1<<30); struct Edge { int v,next; int w; } ep[MAXV*MAXV]; int first[MAXV]; int d[MAXV]; int e; int V; inline void init(int n) { memset(first,-1,sizeof(first)); e=0; V=n; } void addEdge(int u, int v, int dd) { ep[e].v=v; ep[e].w=dd; ep[e].next=first[u]; first[u]=e++; } void solve(int source) { static bool ok[MAXV]; memset(ok,false,sizeof(ok)); queue<int> q; q.push(source); for (int i = 0; i < V; i++) d[i] = INF; d[source] = 0; while(!q.empty()) { int x=q.front();q.pop(); ok[x]=false; for(int k=first[x];k!=-1;k=ep[k].next) { int v=ep[k].v; if(d[v]<d[x]+ep[k].w) { d[v]=d[x]+ep[k].w; if(ok[v]==false) { ok[v]=true; q.push(v); } } } } } } g; struct TarJan { struct Edge { int v,next; }edge[4*MAXV]; int first[MAXV],ins[MAXV],dfn[MAXV],low[MAXV],Stack[MAXV],scc[MAXV]; int top,index,sccnum,e,V; void init (int n) { e=0;V=n; memset(first,-1,sizeof(first[0])*n);memset(ins,0,sizeof(ins[0])*n); memset(dfn,0,sizeof(dfn[0])*n); memset(low,0,sizeof(dfn[0])*n); } void addEdge(int u,int v) { edge[e].v=v;edge[e].next=first[u];first[u]=e++;} void solve() { index=1;top=-1;sccnum=-1; for(int i=0;i<V;i++)if(dfn[i]==0) tarjan(i); } void tarjan(int u) { int v; low[u] = dfn[u] = index++; Stack[++top]=u; ins[u] = true; for (int k=first[u]; k!=-1; k=edge[k].next) { v = edge[k].v; if (dfn[v] == 0) { tarjan(v); low[u]=min(low[u],low[v]); } else if (ins[v]) { low[u]=min(low[u],dfn[v]); } } if (dfn[u] == low[u]) { sccnum++; do{v = Stack[top--];ins[v] = false; scc[v] = sccnum;}while(u != v); } } }my; void init() { int x,y; memset(value,0,sizeof(value)); my.init(n*m); for(int i=0;i<n;i++) { for(int j=0;j<m;j++) if(graph[i][j]!='#') { if(i!=0) my.addEdge((i-1)*m+j,i*m+j); if(j!=0) my.addEdge(i*m+j-1,i*m+j); if(graph[i][j]=='*') { scanf("%d%d",&x,&y); if(graph[x][y]!='#') my.addEdge(i*m+j,x*m+y); } } } my.solve(); } void solve() { g.init(my.sccnum+2); for(int i=0;i<n;i++) for(int j=0;j<m;j++) { if(graph[i][j]!='*'&&graph[i][j]!='#') { value[my.scc[i*m+j]]+=graph[i][j]-'0'; } } for(int i=0;i<n*m;i++) { for(int k=my.first[i];k!=-1;k=my.edge[k].next) { int v=my.edge[k].v; if(my.scc[i]!=my.scc[v]) { g.addEdge(my.scc[i],my.scc[v],value[my.scc[v]]); } } } int ans=0; g.solve(my.scc[0]); for(int i=0;i<=my.sccnum;i++) { if(g.d[i]>ans) ans=g.d[i]; } printf("%d\n",ans+value[my.scc[0]]); } int main() { int ca; scanf("%d",&ca); while(ca--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) { scanf("%s",graph[i]); } init(); solve(); } return 0; }