题意:给出一个矩阵宫室(Very Very Large!!!),该宫室中只有拥有传送门的密室才有宝藏,而传送门分为三种,它们分别是:
-
“横天门”:由该门可以传送到同行的任一宫室;
-
“纵寰门”:由该门可以传送到同列的任一宫室;
-
“任意门”:由该门可以传送到以该门所在宫室为中心周围8格中任一宫室(如果目标宫室存在的话)。
而我们的主人公 Henry先生有一个便携式传送门,但它只有在进入宫室和和离开宫室时使用,而且它可以在任意密室使用(不管该密室有没有传送门),问 Henry先生该怎么走,才能经过尽可能多的密室;
解法:恶心建图+Tarjan缩点+DAG;
-
恶心建图;这应该是本题的难点;对于 横天门 和 纵寰门 ,我们可以分别开一个 vector数组记录,而对于 任意门 ,我们则需要用到 Hash+map ;
-
Tarjan+缩点;这个做法应该是人人都能够看出来的,就不多说了;
-
DAG;在缩完点后,图就变成了 DAG,这个时候我们可以建立一个超级源点,然后跑一遍最长路就可以了(当然,也可以topu);
附上代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<ctime> #include<queue> #include<map> #define ll long long #define rg register using namespace std; const int N = 1e5+10; inline int read(){ int ref=0,x=1;char ch=getchar(); while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) ref=ref*10+ch-'0',ch=getchar(); return ref*x; } int T,n,m; struct edge{ int next,to,w; }e[N*10]; struct node{ int x,y,z; }a[N]; int head[N],cnt; int dx[]={-1,1,0,0,-1,-1,1,1},dy[]={0,0,-1,1,-1,1,-1,1}; map<ll ,int > mp; vector<int > row[N],line[N],g[N]; int dfn[N],low[N],f[N],co[N],sta[N]; int tot,top,col; int dp[N],vis[N],in[N],ans; inline void add(int u,int v,int w){ e[++cnt]=(edge){head[u],v,w}; head[u]=cnt; } ll get(int x,int y){ return 1ll*(x-1)*m+y; } inline void tarjan(int x){ dfn[x]=low[x]=++tot; sta[++top]=x; for(int i=0;i<g[x].size();++i){ int v=g[x][i]; if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]); else if(!co[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]){ co[x]=++col; f[col]++; while(sta[top]!=x){ co[sta[top]]=col; f[col]++; top--; } top--; } } void spfa(){ queue<int > q; q.push(0); dp[0]=0; vis[0]=1; while(!q.empty()){ int x=q.front(); q.pop(); vis[x]=0; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(dp[v]<dp[x]+e[i].w){ dp[v]=dp[x]+e[i].w; if(!vis[v]) vis[v]=1,q.push(v); } } } } int main() { T=read(),n=read(),m=read(); for(int i=1;i<=T;++i){ a[i].x=read(),a[i].y=read(),a[i].z=read(); row[a[i].x].push_back(i); line[a[i].y].push_back(i); mp[get(a[i].x,a[i].y)]=i; } for(int i=1;i<=T;++i){ if(a[i].z==1){ for(rg int j=0;j<row[a[i].x].size();++j){ if(row[a[i].x][j]==i) continue; g[i].push_back(row[a[i].x][j]); } } if(a[i].z==2){ for(rg int j=0;j<line[a[i].y].size();++j){ if(line[a[i].y][j]==i) continue; g[i].push_back(line[a[i].y][j]); } } if(a[i].z==3){ for(rg int j=0;j<8;++j){ int fx=a[i].x+dx[j],fy=a[i].y+dy[j]; if(fx<1||fx>n||fy<1||fy>m) continue; if(mp[get(fx,fy)]) g[i].push_back(mp[get(fx,fy)]); } } } for(int i=1;i<=T;++i) if(!dfn[i]) tarjan(i); f[0]=0; for(int i=1;i<=T;++i){ if(!in[co[i]]) add(0,co[i],f[co[i]]),in[co[i]]=1; for(rg int j=0;j<g[i].size();++j){ int v=g[i][j]; int uu=co[i],vv=co[v]; if(uu==vv) continue; add(uu,vv,f[vv]); } } spfa(); for(int i=1;i<=col;++i) ans=max(ans,dp[i]); printf("%d",ans); return 0; }