题目描述
从机房到食堂的地图可以简化为一张n个点m条边的有向图,通过每条边需要一定的时间。机房在1号节点,食堂在n号节点。膜法师hercier 使用结界将食堂和一些点封锁了起来使其无法通过,如果想通过某个节点,你就必须破坏掉维持这个节点结界的所有结界发生器。幸运的是,你在上一题的未知森林里领悟了分身术,你可以分出无限多的分身去破坏结界发生器,normalgod 想知道你最早什么时候能到达食堂,请你写个程序告诉他。(破坏瞬间完成,分身移动速度与本体相同)
题解
我们的限制像是一个拓扑图,那么我们可以跑两张图,一张拓扑图,一张原图,当拓扑图内的点入度为0时将这个点加入松弛,原图的距离更新为max(原图距离,拓扑图距离)。、
代码
#include <bits/stdc++.h>
#define maxn 10005
#define MAXN 70005
#define INF 0x3f3f3f3f
#define LL long long
#define P pair<int,int>
#define mp make_pair
using namespace std;
int read(){
int res,f=1; char c;
while(!isdigit(c=getchar())) if(c=='-') f=-1; res=(c^48);
while(isdigit(c=getchar())) res=(res<<3)+(res<<1)+(c^48);
return res*f;
}
struct EDGE{
int u,v,w,nxt;
}e[MAXN];
struct NODE{
int dis,id;
bool operator < (const NODE& rhs)const{return dis>rhs.dis;}
};
int n,m,cnt,du[maxn],head[maxn];
void add(int u,int v,int w){e[++cnt]=(EDGE){u,v,w,head[u]}; head[u]=cnt;}
vector<int> q[maxn];
priority_queue<NODE> Q;
LL dis[maxn],Dis[maxn];
void Dijstra(int s){
memset(dis,0x3f,sizeof dis); dis[s]=0;
Q.push((NODE){0,s});
while(!Q.empty()){
int u=Q.top().id,d=Q.top().dis; Q.pop();
if(d^dis[u]) continue;
dis[u]=max(dis[u],Dis[u]);
for(int i=0;i<q[u].size();i++){
int v=q[u][i];
du[v]--; Dis[v]=max(dis[u],Dis[v]);
if(!du[v]) Q.push((NODE){dis[v],v});
}
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].v,w=e[i].w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!du[v]) Q.push((NODE){dis[v],v});
}
}
}
}
int main(){
memset(head,-1,sizeof head);
n=read(); m=read();
for(int i=1,u,v,w;i<=m;i++){
u=read(); v=read(); w=read(); add(u,v,w);
}
for(int i=1,s,x;i<=n;i++){
du[i]=read();
if(n==1 && s) {puts("-1"); return 0;}
for(int j=1;j<=du[i];j++) q[read()].push_back(i);
}
Dijstra(1);
printf("%d\n",dis[n]);
return 0;
}