
题意:有一片 n*m 的矿地,每一格有矿、或这传送门、或者挡路岩石。除了岩石不能走以外,其他的格子都能够向右或向下走,走到一个非岩石的格子。对于每一个矿点,经过它就能得到它的所有矿石,而对于每一个传送门,你可以选择传送或者不传送,向右或向下继续走(传送门送达点也可能是岩石),按从上到下、从左到右的顺序对于每一个传送门给定一个传送点。问最多能够获得多少矿石。
对于这样一张图,我们能够发现,有一些点,由于传送门的存在,一定可以相互到达,那么这些点可以按强连通缩点,之后对于有向无环图就可以很轻松地用记忆化搜索得到最大值了。
#include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
using namespace std; const int maxn=;
const int maxm=1e5; char s[][];
int head[][maxn],point[][maxm],nxt[][maxm],size[];
int n,t,scccnt;
int stx[maxn],low[maxn],scc[maxn],num[maxn],v[maxn];
int dp[maxn];
stack<int>S; int max(int a,int b){return a>b?a:b;} void init(){
memset(head,-,sizeof(head));
size[]=size[]=;
memset(num,,sizeof(num));
memset(dp,-,sizeof(dp));
} void add(int a,int b,int c=){
point[c][size[c]]=b;
nxt[c][size[c]]=head[c][a];
head[c][a]=size[c]++;
} void dfs(int s){
stx[s]=low[s]=++t;
S.push(s);
for(int i=head[][s];~i;i=nxt[][i]){
int j=point[][i];
if(!stx[j]){
dfs(j);
low[s]=min(low[s],low[j]);
}
else if(!scc[j]){
low[s]=min(low[s],stx[j]);
}
}
if(low[s]==stx[s]){
scccnt++;
while(){
int u=S.top();S.pop();
scc[u]=scccnt;
num[scccnt]+=v[u];
if(s==u)break;
}
}
} void setscc(){
memset(stx,,sizeof(stx));
memset(scc,,sizeof(scc));
t=scccnt=;
for(int i=;i<=n;++i)if(!stx[i])dfs(i);
for(int i=;i<=n;++i){
for(int j=head[][i];~j;j=nxt[][j]){
int k=point[][j];
if(scc[i]!=scc[k]){
add(scc[i],scc[k],);
}
}
}
} int Dp(int s){
if(~dp[s])return dp[s];
int maxx=;
for(int i=head[][s];~i;i=nxt[][i]){
maxx=max(maxx,Dp(point[][i]));
}
return dp[s]=num[s]+maxx;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int m,l;
scanf("%d%d",&l,&m);
n=m*l;
init();
for(int i=;i<=l;++i)scanf("%s",s[i]+);
int a,b;
for(int i=;i<=l;++i){
for(int j=;j<=m;++j){
int p=(i-)*m+j;
if(s[i][j]>=''&&s[i][j]<=''){
v[p]=s[i][j]-'';
}
else v[p]=;
if(s[i][j]!='#'){
if(i+<=l&&s[i+][j]!='#'){
add(p,p+m);
}
if(j+<=m&&s[i][j+]!='#'){
add(p,p+);
}
}
if(s[i][j]=='*'){
scanf("%d%d",&a,&b);
a++;
b++;
if(s[a][b]!='#'){
int p1=(a-)*m+b;
add(p,p1);
}
}
}
}
setscc();
printf("%d\n",Dp(scc[]));
}
return ;
}