题目链接

Tarjan+dp

建图: 矩阵中的每一个点作为一个节点,分别指向右边和下面不是#的点,单向建边,如果遇到*, 要多加一条指向*传送的点的单向边。

强连通图内的所有权值都是可取的,缩点之后,图会变成一个森林,用dfs搜索,并用dp数组记忆化数据,下次dfs到这个点时,直接取dp值即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>

using namespace std;

typedef long long ll;

const int MaxnN = 40*40+10;
const int MaxnE = 40*40*40*40+10;
const int INF = 0x3f3f3f3f;
const int Mod = 1e9+7;

vector <int> G[MaxnN], vG[MaxnN];
int dfn[MaxnN], low[MaxnN], scc, num[MaxnN];
int cost[MaxnN], Ncost[MaxnN], dp[MaxnN];
int Stack[MaxnN], Top, indx;
int n, m;
char s[MaxnN][MaxnN];

void Tarjan(int u) {
    dfn[u] = low[u] = ++indx;
    Stack[Top++] = u;
    int len = G[u].size();
    for(int i = 0; i < len; ++i) {
        int v = G[u][i];
        if(!dfn[v]) {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        } else if(!num[v]) low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]) {
        scc++;
        int v;
        do {
            v = Stack[--Top];
            num[v] = scc;
            Ncost[scc] += cost[v];
        } while(u != v);
    }
}

void dfs(int u) {
    if(dp[u]) return;
    int len = vG[u].size(), sum = 0;
    for(int i = 0; i < len; ++i) {
        int v = vG[u][i];
        if(!dp[v]) dfs(v);
        sum = max(sum, dp[v]);
    }
    dp[u] = sum+Ncost[u];
}

int id(int x, int y) {
    return (x*m+y);
}

int main(void)
{
	int T;
	scanf("%d", &T);
	while(T--) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; ++i) scanf("%s", s[i]);
        for(int i = 0; i <= n*m; ++i) G[i].clear();
        int x, y;
        for(int i = 0; i < n; ++i) {
            for(int j = 0; j < m; ++j) {
                if(s[i][j] == '#') {
                    cost[id(i, j)] = 0;
                } else {
                    if(s[i][j] == '*') {
                        cost[id(i, j)] = 0;
                        scanf("%d%d", &x, &y);
                        if(s[x][y] != '#') G[(id(i, j))].push_back(id(x, y));
                    }
                    else cost[id(i, j)] = s[i][j]-'0';
                    if(i+1 < n && s[i+1][j] != '#') G[id(i, j)].push_back(id(i+1, j));
                    if(j+1 < m && s[i][j+1] != '#') G[id(i, j)].push_back(id(i, (j+1)));
                }
            }
        }
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(num, 0, sizeof(num));
        memset(Ncost, 0, sizeof(Ncost));
        scc = Top = indx = 0;
        for(int i = 0; i < n*m; ++i) if(!dfn[i]) Tarjan(i);

        for(int i = 1; i <= scc; ++i) vG[i].clear();
        for(int i = 0; i < n*m; ++i) {
            int len = G[i].size();
            for(int j = 0; j < len; ++j) {
                int v = G[i][j];
                if(num[i] != num[v]) vG[num[i]].push_back(num[v]);
            }
        }
        memset(dp, 0, sizeof(dp));
        dfs(num[0]);
        printf("%d\n", dp[num[0]]);
	}
	return 0;
}