题意:有一片 n*m 的矿地,每一格有矿、或这传送门、或者挡路岩石。除了岩石不能走以外,其他的格子都能够向右或向下走,走到一个非岩石的格子。对于每一个矿点,经过它就能得到它的所有矿石,而对于每一个传送门,你可以选择传送或者不传送,向右或向下继续走(传送门送达点也可能是岩石),按从上到下、从左到右的顺序对于每一个传送门给定一个传送点。问最多能够获得多少矿石。
对于这样一张图,我们能够发现,有一些点,由于传送门的存在,一定可以相互到达,那么这些点可以按强连通缩点,之后对于有向无环图就可以很轻松地用记忆化搜索得到最大值了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=1605;
8 const int maxm=1e5;
9
10 char s[45][45];
11 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
12 int n,t,scccnt;
13 int stx[maxn],low[maxn],scc[maxn],num[maxn],v[maxn];
14 int dp[maxn];
15 stack<int>S;
16
17 int max(int a,int b){return a>b?a:b;}
18
19 void init(){
20 memset(head,-1,sizeof(head));
21 size[0]=size[1]=0;
22 memset(num,0,sizeof(num));
23 memset(dp,-1,sizeof(dp));
24 }
25
26 void add(int a,int b,int c=0){
27 point[c][size[c]]=b;
28 nxt[c][size[c]]=head[c][a];
29 head[c][a]=size[c]++;
30 }
31
32 void dfs(int s){
33 stx[s]=low[s]=++t;
34 S.push(s);
35 for(int i=head[0][s];~i;i=nxt[0][i]){
36 int j=point[0][i];
37 if(!stx[j]){
38 dfs(j);
39 low[s]=min(low[s],low[j]);
40 }
41 else if(!scc[j]){
42 low[s]=min(low[s],stx[j]);
43 }
44 }
45 if(low[s]==stx[s]){
46 scccnt++;
47 while(1){
48 int u=S.top();S.pop();
49 scc[u]=scccnt;
50 num[scccnt]+=v[u];
51 if(s==u)break;
52 }
53 }
54 }
55
56 void setscc(){
57 memset(stx,0,sizeof(stx));
58 memset(scc,0,sizeof(scc));
59 t=scccnt=0;
60 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
61 for(int i=1;i<=n;++i){
62 for(int j=head[0][i];~j;j=nxt[0][j]){
63 int k=point[0][j];
64 if(scc[i]!=scc[k]){
65 add(scc[i],scc[k],1);
66 }
67 }
68 }
69 }
70
71 int Dp(int s){
72 if(~dp[s])return dp[s];
73 int maxx=0;
74 for(int i=head[1][s];~i;i=nxt[1][i]){
75 maxx=max(maxx,Dp(point[1][i]));
76 }
77 return dp[s]=num[s]+maxx;
78 }
79
80 int main(){
81 int T;
82 scanf("%d",&T);
83 while(T--){
84 int m,l;
85 scanf("%d%d",&l,&m);
86 n=m*l;
87 init();
88 for(int i=1;i<=l;++i)scanf("%s",s[i]+1);
89 int a,b;
90 for(int i=1;i<=l;++i){
91 for(int j=1;j<=m;++j){
92 int p=(i-1)*m+j;
93 if(s[i][j]>='0'&&s[i][j]<='9'){
94 v[p]=s[i][j]-'0';
95 }
96 else v[p]=0;
97 if(s[i][j]!='#'){
98 if(i+1<=l&&s[i+1][j]!='#'){
99 add(p,p+m);
100 }
101 if(j+1<=m&&s[i][j+1]!='#'){
102 add(p,p+1);
103 }
104 }
105 if(s[i][j]=='*'){
106 scanf("%d%d",&a,&b);
107 a++;
108 b++;
109 if(s[a][b]!='#'){
110 int p1=(a-1)*m+b;
111 add(p,p1);
112 }
113 }
114 }
115 }
116 setscc();
117 printf("%d\n",Dp(scc[1]));
118 }
119 return 0;
120 }