1. 程式人生 > >DTOJ 4001 分身術(orz)

DTOJ 4001 分身術(orz)

分身術
時間限制: 1 Sec 記憶體限制: 256 MB
題目描述

題目背景:當您再次回到機房時已經是中午了,於是您決定去吃飯。

從機房到食堂的地圖可以簡化為一張 n n 個點, m m 條邊的有向圖,通過每條邊需要一定的時間。機房在1號節點,食堂在n號節點。膜法師 h

e r c i e r hercier 使用結界將食堂和一些點封鎖了起來使其無法通過,如果想通過某個節點,你就必須破壞掉維持這個節點結界的所有結界發生器。幸運的是,你在上一題的未知森林裡領悟了分身術,你可以分出無限多的分身去破壞結界發生器, n
o r m a l g o d normalgod
想知道你最早什麼時候能到達食堂,請你寫個程式告訴他。(破壞瞬間完成,分身移動速度與本體相同)

輸入
第一行 2 2 個整數,分別表示 n , m n,m

之後 m m 行每行三個整數 a , b , c a,b,c ,表示 a a b b 有一條需要走 c c 分鐘的邊。
之後 n n 行每行一個正整數 k k 表示維持這個節點結界的結界發生器數目。

之後 k k 1 n 1-n 之間的節點編號,表示每個結界發生器的位置。
輸出
到達食堂的最早時間,永遠不能到達輸出 1 -1
樣例輸入
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% 的資料,滿足 n 15 , m 50 n≤15,m≤50
對於50% 的資料,滿足 n 500 , m 6000 n≤500,m≤6000
對於另20% 的資料,滿足 k = 0 k=0
對於100% 的資料,滿足 n 3000 , m 70000 , 1 c 1 0 8 n≤3000,m≤70000,1≤c≤10^8。

連線兩個節點的道路可能不止一條, 也可能存在一個節點自己到自己的道路。

題解:
k = = 0 k==0 時,實際上就是一個從 1 1 n n 之間的最短路。
k ! = 0 k!=0 時,考慮這些會帶來限制的點。
對於單獨一個被限制的點,與之相關的一個子圖,你只能按照拓撲序將它一個一個點消掉。
設一個點到 1 1 的最短路為 d i s i dis_{i} ,與之相關的就是在他所在子圖上拓撲序與之相關的點。
於是我們在做最短路 d i j k s t r a dijkstra 中,往下轉移作拓撲排序。
h x h_{x} 就表示在 x x 點,在拓撲序與之相鄰的點轉移來的 d i s dis 值。
並且只有當某個點入度為 0 0 時才會進優先佇列。

#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]);
}