题意:有一片 n*m 的矿地,每一格有矿、或这传送门、或者挡路岩石。除了岩石不能走以外,其他的格子都能够向右或向下走,走到一个非岩石的格子。对于每一个矿点,经过它就能得到它的所有矿石,而对于每一个传送门,你可以选择传送或者不传送,向右或向下继续走(传送门送达点也可能是岩石),按从上到下、从左到右的顺序对于每一个传送门给定一个传送点。问最多能够获得多少矿石。

对于这样一张图,我们能够发现,有一些点,由于传送门的存在,一定可以相互到达,那么这些点可以按强连通缩点,之后对于有向无环图就可以很轻松地用记忆化搜索得到最大值了。

  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 }
View Code