DTOJ 4001 分身術(orz)
分身術
時間限制: 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]);
}