题意:
n*m矩阵,*表示传送门,矩阵后面给出其到达的点,#障碍点,不可到达,数字表示该点的宝藏数,每个点可以往下或者往右走,获得宝藏后该点宝藏数变为0,问最多能获得多少宝藏。
思路:
建图+强连通缩点+拓扑dp。
难点:
构图:#点不可做为起点也不可以作为终点。总共n*m个点,标号别和其他量弄混。
强连通缩点:只对“1”所处的块tarjan即可,拓扑序同理。
AC代码:
/**Wjvje**/
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include<algorithm>
#include <set>
#include <queue>
#include <stack>
#include<vector>
#include<map>
#include<ctime>
/** -?£- **/
#define LL long long
#define par pair<LL,int>
#define INF 0x3f3f3f3f
#define io ios::sync_with_stdio(false)
using namespace std;
const int N=1600+100;
const int M=3e6+100;
int head[N];
int ver[M];
int Next[M];
int tot;
void add(int x,int y)
{
ver[++tot]=y;
Next[tot]=head[x];
head[x]=tot;
}
int hc[N];
int vc[M];
int nc[M];
int tc;
int n,m;
int dfn[N],low[N];
int stackk[N],ins[N],c[N];
int num=0;
int top;//指针
int cnt;//强联通分量标号
int value2[N];
int value[N];
void tarjan(int x)
{
dfn[x]=low[x]=++num;
stackk[++top]=x;
ins[x]=1;
for(int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if(!dfn[y])
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y])
{
low[x]=min(low[x],low[y]);
}
}
if(dfn[x]==low[x])
{
cnt++;
int y;
do
{
y=stackk[top--];
ins[y]=0;
c[y]=cnt;
value2[cnt]+=value[y];//value2缩点后,value缩点前
//cout<<y<<".."<<value2[cnt]<<endl;
}
while(x!=y);
}
}
int to[N];
int deg[N];
void add_c(int x,int y)
{
vc[++tc]=y;
nc[tc]=hc[x];
hc[x]=tc;
deg[y]++;
}
int kk;
void topsort(int nn)
{
queue<int> q;
kk=0;
while(q.size())q.pop();
for(int i=1;i<=nn;++i)
if(deg[i]==0)q.push(i);
while(q.size())
{
int x=q.front();
q.pop();
to[++kk]=x;
for(int i=hc[x];i;i=nc[i])
{
int y=vc[i];
if(--deg[y]==0)q.push(y);
}
}
}
char ch[101][101];
int mer[N];
int cal(int x,int y)
{
return (x-1)*m+y;
}
bool judge(int x,int y)
{
return x>=1&&x<=n&&y>=1&&y<=m;
}
bool mark[2000][2000];
int dp[N];
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m;
kk=0;
memset(dp,0,sizeof(dp));
memset(ch,'0',sizeof(ch));
memset(to,0,sizeof(to));
memset(value,0,sizeof(value));
memset(value2,0,sizeof(value2));
memset(mer,0,sizeof(mer));
memset(head,0,sizeof(head));
memset(Next,0,sizeof(Next));
memset(ver,0,sizeof(ver));
memset(ins,0,sizeof(ins));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(stackk,0,sizeof(stackk));
memset(c,0,sizeof(c));
tot=1;
memset(hc,0,sizeof(hc));
memset(nc,0,sizeof(nc));
memset(vc,0,sizeof(vc));
memset(mark,0,sizeof(mark));
tc=1;
num=cnt=top=0;
int tmp=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
cin>>ch[i][j];
if(ch[i][j]=='*')mer[++tmp]=cal(i,j);//记录传送门
}
}
for(int i=1;i<=tmp;++i)
{
int x,y;
cin>>x>>y;
x+=1;
y+=1;
int index=cal(x,y);
if(ch[x][y]!='#')
{
add(mer[i],index);
mark[mer[i]][index]=1;
}
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(ch[i][j]=='#')continue;
else
{
if(ch[i][j]=='*')value[cal(i,j)]=0;//特判
else value[cal(i,j)]=ch[i][j]-'0';
int index=cal(i,j);
if(judge(i+1,j)&&mark[index][cal(i+1,j)]==0&&ch[i+1][j]!='#')add(index,cal(i+1,j));
if(judge(i,j+1)&&mark[index][cal(i,j+1)]==0&&ch[i][j+1]!='#')add(index,cal(i,j+1));
}
}
}
tarjan(1);
for(int i=1; i<=n; ++i)
for(int j=1;j<=m;++j)
{
int index=cal(i,j);
if(dfn[index]==0)continue;//不属于1的块
if(ch[i][j]=='#')continue;
for(int k=head[index]; k; k=Next[k])
{
int y=ver[k];
if(dfn[y]==0)continue;
if(c[index]==c[y])continue;
add_c(c[index],c[y]);
}
}
//cout<<cnt<<endl;
topsort(cnt);
int pos=0;
for(int i=1;i<=cnt;++i)
{
if(to[i]==c[1])
{
pos=i;
break;
}
}
dp[to[pos]]=value2[to[pos]];
int ans=dp[to[pos]];
//cout<<ans<<endl;
for(int i=pos;i<=cnt;++i)
{
int x=to[i];
//cout<<x<<endl;
for(int j=hc[x];j;j=nc[j])
{
int y=vc[j];
dp[y]=max(dp[y],dp[x]+value2[y]);
ans=max(ans,dp[y]);
}
}
cout<<ans<<endl;
}
return 0;
}
The end;