signed

QiShunwang

“诚信为本、客户至上”

HDU - 3873

2021/3/21 10:25:55   来源:

首先由题意可以知道
1.你到达一个城市 若他有保护罩 你必须去保存保护罩发射器的地方去摧毁掉
2.他是有很多人可以同时进行
3.若你到达了一个地方 但是他的保护罩没有摧毁掉 你必须摧毁掉他的保护罩
才能算完全到达

由上面知道 首先这是一个拓扑图

然后只需要从能跑的地方一个一个跑接下来的地方即可

#include<iostream>
#include<cstring>
#include<vector>
#include<utility> 
#include<queue>
#define x first
#define y second

using namespace std;

const int N = 3100,M = 7e4 + 10;

typedef long long ll;

typedef pair<ll,int> PII;

int head[N],to[M];ll w[M];int last[M],cnt;
void add(int a,int b,ll c){
	to[++cnt] = b;
	w[cnt] = c;
	last[cnt] = head[a];
	head[a] = cnt;
}

vector<int>v[N];

int n,m;

ll dist[N];int flag[N],de[N];ll dt[N];
void dij(){
	memset(flag,0,sizeof flag);
	memset(dt,0,sizeof dt);
	priority_queue<PII,vector<PII>,greater<PII > > q;
	for(int i = 1; i <= n; i++){
		dist[i] = 1e18;
	}
	q.push({0,1});
	dist[1] = 0;
	while(q.size()){
		PII p = q.top();
		q.pop();
		if(flag[p.y]) continue;
		flag[p.y] = 1;
		for(auto i : v[p.y]){
			de[i]--;
			dt[i] = max(dt[i],dt[p.y]);
			if(de[i] == 0 && dist[i] != 1e18){
				dist[i] = max(dist[i],dt[i]); //如果他已经全部跑完了 跑过了并且已经是最短路了 他必须要比摧毁保护罩的时间大或者等于
				q.push({dist[i],i});
			}
		}
		for(int i = head[p.y]; i != -1; i = last[i]){
			int j = to[i];
			if(dist[j] > dist[p.y] + w[i]){
				dist[j] = max(dist[p.y] + w[i],dt[j]); //更新
				if(de[j] == 0) q.push({dist[j],j}); //如果没有跑完de[j]更新的话 后面的所有都是错误的 那更新会很麻烦
			}
		}
	}
}

int main(){
	int t;
	cin >> t;
	while(t--){
		memset(head,-1,sizeof head);
		memset(de,0,sizeof de);
		cnt = 0;
		scanf("%d%d",&n,&m);
		for(int i = 0; i <= n; i++){
			v[i].clear();
		}
		for(int i = 1; i <= m; i++){
			int x,y;ll z;
			scanf("%d%d%lld",&x,&y,&z);
			add(x,y,z);
		}
		
		for(int i = 1; i <= n; i++){
			int x,y;
			scanf("%d",&x);
			for(int j = 1; j <= x; j++){
				scanf("%d",&y);
				v[y].push_back(i);
				de[i]++;
			}
		}
		
		dij();
		
		cout << dist[n] << endl; 
		
	}
	
	
	
	
	
	return 0;
}