总时间限制:1000ms 内存限制:32768kB
-
描述
-
你在一个N*M的区域中,一开始在(1,1)的位置,每个位置有可能有金子,也有可能不能到达,也有可能有传送门。你只能往右或者下走,不能走出这个区域。当你位于传送门时,传送门你可以选择使用或者不使用,使用的次数无限,若使用则传送到传送门指定的位置。每个位置的金子你可以拿走它,问最后你最多能够拿走多少金子。
-
输入
-
首先测试数据组数T。
对于每组测试数据,先输入两个整数N,M(2<=N,M<=40)。
接下来是一个N*M的矩阵,表示每个位置的内容X,若0<=X<=9,表示该位置的金子个数为X,若X为'*',表示该位置有一个传送门,若X为'#',表示该位置不可到达。
假设传送门的个数为K个,接下来K行,每行两个整数x,y(x大于等于0小于n,y大于等于0小于m),依次表示每个传送门传送的位置,顺序是从第一行开始从上到下扫描,每一行从左往右扫描。 -
输出
- 对于每组数据,输出能够得到的最多的金子的个数。
-
样例输入
-
1 2 2 11 1* 0 0
- 样例输出
-
3
传送门到传送点之间的区域是一个强连通分图,可以缩成图上的一个点,再用记忆化搜索求解。
#include <stdio.h>
#include <string.h>
#include<iostream>
#include <vector>
#include <stack>
#include<queue>
using namespace std;
#define INF 999999
#define MIN(a,b) ((a)<(b)?(a):(b))
#define N 2500 // 题目中可能的最大点数
stack<int>sta; // 存储已遍历的结点
vector<int>gra[N]; // 邻接表表示图
int dfn[N]; // 深度优先搜索访问次序
int low[N]; // 能追溯到的最早的次序
int InStack[N]; // 检查是否在栈中(2为在栈中,1为已访问,且不在栈中,0为不在)
vector<int> Component[N]; // 获得强连通分量结果
int InComponent[N]; // 记录每个点在第几号强连通分量里
int indexx,ComponentNumber; // 索引号,强连通分量个数
int map[50][50]; // 映射
int high,wight; // 图高宽
int cnt; // 点数
int gatex[N]; // 传送门坐标
int gatey[N];
int goal[50][50]; // 每点金子数
int Component_goal[N]; // 每强连通分量金子数
int num_gate; // 传送门数量
int ans; // 最多金子数
vector<int>gra_c[N]; //邻接表缩点图
int dp[N]; //记忆化搜索
void init(void)
{
ans=0;
cnt=0;
num_gate=0;
for(int i=0;i<high;++i){
for(int j=0;j<wight;++j){
cnt++;
map[i][j]=cnt;
}
}
memset(dp,-1,sizeof(dp));
memset(goal,0,sizeof(goal));
memset(Component_goal,0,sizeof(Component_goal));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(InStack, 0, sizeof(InStack));
indexx = ComponentNumber = 0;
for (int i = 1; i <= cnt; ++ i)
{
gra[i].clear();
Component[i].clear();
gra_c[i].clear();
}
while(!sta.empty())
sta.pop();
}
void tarjan(int u)
{
InStack[u] = 2;
low[u] = dfn[u] = ++ indexx;
sta.push(u);
for (int i = 0; i < gra[u].size(); ++ i)
{
int t = gra[u][i];
if (dfn[t] == 0)
{
tarjan(t);
low[u] = MIN(low[u], low[t]);
}
else if (InStack[t] == 2)
{
low[u] = MIN(low[u], dfn[t]);
}
}
if (low[u] == dfn[u])
{
++ ComponentNumber;
while (!sta.empty())
{
int j = sta.top();
sta.pop();
InStack[j] = 1;
Component[ComponentNumber].push_back(j);
InComponent[j]=ComponentNumber;
if (j == u)
break;
}
}
}
int DFS(int x){
if(dp[x]!=-1)
return dp[x];
else{
int mmax=0;
for(int i=0;i<gra_c[x].size();++i){
mmax=max(mmax,DFS(gra_c[x][i]));
}
dp[x]=Component_goal[x]+mmax;
return dp[x];
}
}
void input(void)
{
for(int i=0;i<high;++i){
for(int j=0;j<wight;++j){
char ch=getchar();
if(ch>='0'&&ch<='9')
goal[i][j]=ch-'0';
else if(ch=='#')
goal[i][j]=-1;
else if(ch=='*'){
goal[i][j]=0;
num_gate++;
gatex[num_gate]=i;
gatey[num_gate]=j;
}
}
getchar();
}
for(int i=0;i<high;++i){
for(int j=0;j<wight;++j){
if(goal[i][j]==-1)continue;
if(i+1<high&&goal[i+1][j]!=-1)
gra[map[i][j]].push_back(map[i+1][j]);
if(j+1<wight&&goal[i][j+1]!=-1)
gra[map[i][j]].push_back(map[i][j+1]);
}
}
for(int i=1;i<=num_gate;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(goal[a][b]!=-1)
gra[map[gatex[i]][gatey[i]]].push_back(map[a][b]);
}
}
void solve(void)
{
for(int i=1;i<=cnt;i++){
if(!dfn[i])
tarjan(i);
}
for(int i=0;i<high;++i){
for(int j=0;j<wight;++j){
Component_goal[InComponent[map[i][j]]]+=goal[i][j];
}
}
for(int i=1;i<=cnt;++i){
for(int j=0;j<gra[i].size();++j){
if(InComponent[i]==InComponent[gra[i][j]])continue;
gra_c[InComponent[i]].push_back(InComponent[gra[i][j]]);
}
}
ans=DFS(InComponent[map[0][0]]);
printf("%d\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d\n",&high,&wight);
init();
input();
solve();
}
return 0;
}