分身术
时间限制: 1 Sec 内存限制: 256 MB
题目描述
题目背景:当您再次回到机房时已经是中午了,于是您决定去吃饭。
从机房到食堂的地图可以简化为一张 个点, 条边的有向图,通过每条边需要一定的时间。机房在1号节点,食堂在n号节点。膜法师 使用结界将食堂和一些点封锁了起来使其无法通过,如果想通过某个节点,你就必须破坏掉维持这个节点结界的所有结界发生器。幸运的是,你在上一题的未知森林里领悟了分身术,你可以分出无限多的分身去破坏结界发生器, 想知道你最早什么时候能到达食堂,请你写个程序告诉他。(破坏瞬间完成,分身移动速度与本体相同)
输入
第一行
个整数,分别表示
。
之后
行每行三个整数
,表示
到
有一条需要走
分钟的边。
之后
行每行一个正整数
表示维持这个节点结界的结界发生器数目。
之后
个
之间的节点编号,表示每个结界发生器的位置。
输出
到达食堂的最早时间,永远不能到达输出
。
样例输入
6 6
1 2 1
1 4 3
2 3 1
2 5 2
4 6 2
5 3 2
0
0
0
1 3
0
2 3 5
样例输出
5
提示
对于20% 的数据,满足
对于50% 的数据,满足
对于另20% 的数据,满足
对于100% 的数据,满足
连接两个节点的道路可能不止一条, 也可能存在一个节点自己到自己的道路。
题解:
当
时,实际上就是一个从
到
之间的最短路。
当
时,考虑这些会带来限制的点。
对于单独一个被限制的点,与之相关的一个子图,你只能按照拓扑序将它一个一个点消掉。
设一个点到
的最短路为
,与之相关的就是在他所在子图上拓扑序与之相关的点。
于是我们在做最短路
中,往下转移作拓扑排序。
设
就表示在
点,在拓扑序与之相邻的点转移来的
值。
并且只有当某个点入度为
时才会进优先队列。
#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i--)
#define For(i,a,b) for(re int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
typedef long long ll;
const int N=6004,M=14e4+4;
struct E{int to,nxt;ll w;}e[M<<1];
int head[N],tot,d[N];
in void ins(int x,int y,ll z){
e[++tot]=E{y,head[x],z},head[x]=tot;
}
ll h[N],n,m,ind[N],out[N],dis[N],inf,faq[N];
typedef pair<ll,int>P;
vector<int>v[N];bool vis[N];
#define mk(a,b) make_pair((a),(b))
#define fi first
#define se second
in void dj(){
priority_queue<P,vector<P>,greater<P> >q;
memset(dis,0x3f,sizeof(dis));inf=dis[2];dis[1]=0;
q.push(mk(0,1));
while(!q.empty()){
P now=q.top();q.pop();
int x=now.se;
if(vis[x]) continue; vis[x]=1;
For(i,0,v[x].size()){
int to=v[x][i];ind[to]--;
faq[to]=max(faq[to],dis[x]);
if(!ind[to]&&dis[to]!=inf){
dis[to]=max(dis[to],faq[to]);
q.push(mk(dis[to],to));
}
}
for(int i=head[x];i;i=e[i].nxt){
dis[e[i].to]=max(dis[e[i].to],faq[e[i].to]);
if(dis[e[i].to]>dis[x]+e[i].w){
dis[e[i].to]=dis[x]+e[i].w;
if(!ind[e[i].to]) q.push(mk(dis[e[i].to],e[i].to));
}
}
}
}
int main(){
//freopen(".in","r",stdin);freopen(".out","w",stdout);
g(n),g(m);
rep(i,1,m){
int x,y,z;
g(x),g(y),g(z);
ins(x,y,z);
}
rep(i,1,n){
int t;g(t);
if(i==1&&t) return puts("-1");
while(t--){
int x; g(x);
v[x].push_back(i);
ind[i]++;
}
}dj();
return !printf("%lld\n",(dis[n]>=inf)?-1:dis[n]);
}