solution:
带限制的最短路,可以用dijkstra或者spfa实现,只需在更新加入队列的时候稍作改动
dis为到达的最短时间,d为摧毁所有结界时间,则真实时间为两个值取max
要用这个max去更新其他点
dijkstra更新dis的时候,只有当v的结界全部被摧毁才进堆。
同时将所有结界发生器在当前点的点的结界数量--,如果减为0,进堆。
注意只有这个点出队的时候才说明这个点的结界没了,才能将其他点结界数-1
并且进堆的时候要将max值进堆,但不修改dis和 d的值,最后答案也要取max
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#define N 3005
#define M 70005
#define LL long long
using namespace std;
int n,m,cnt,head[N],num[N];
LL dis[N],d[N];
bool vis[N];
priority_queue< pair<LL,int> > q;
vector<int> vec[N];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();}
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct EDGE{
int to,nxt,w;
}edge[M];
inline void add(int x,int y,int z){
edge[++cnt].to=y;
edge[cnt].nxt=head[x];
edge[cnt].w=z;
head[x]=cnt;
}
inline LL max(LL a,LL b) {return a>b?a:b;}
inline void dijkstra(){
memset(dis,0x3f,sizeof dis);
dis[1]=0; q.push(make_pair(0,1));
while(!q.empty()){
int u=q.top().second; q.pop(); if(vis[u]) continue; vis[u]=1;
LL mx=max(dis[u],d[u]);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(dis[v]>mx+edge[i].w){
dis[v]=mx+edge[i].w;
LL tmp=max(dis[v],d[v]);
if(!num[v]) q.push(make_pair(-tmp,v));
}
}
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i];
num[v]--; d[v]=max(d[v],mx);
LL tmp=max(d[v],dis[v]);
if(!num[v]) q.push(make_pair(-tmp,v));
}
}
}
int main(){
n=rd(); m=rd();
for(int i=1;i<=m;i++){
int x=rd(),y=rd(),z=rd();
add(x,y,z);
}
for(int i=1;i<=n;i++){
num[i]=rd();
for(int j=1;j<=num[i];j++){
int x=rd();
vec[x].push_back(i);
}
}
dijkstra();
printf("%lld\n",max(dis[n],d[n]));
return 0;
}