其实这个题一点都不难,然而我WA了一天。。。因为unidirectional是单向的!。。。原谅我英语渣。。。
思路:优先队列里维护未保护的节点,不断求Dijkstra,对于被保护的节点,开一个pro数组 记录某节点的所有保护它的节点的最晚被占领的时间,当该节点的所有保护它的节点都被攻占时,dis[i] = max(dis[i],pro[i]),此时i节点也可入优先队列了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<iostream>
#include<functional>
using namespace std;
typedef pair<int,int> P;
const int maxn = 3005;
const int inf = 0x3f3f3f3f;
int n,m;
int cnt[maxn],dis[maxn];
int pro[maxn];
vector<int> link[maxn];
priority_queue<P,vector<P>,greater<P> > que;
struct Edge{
int to,cost;
};
vector<Edge> G[maxn];
void init(){
memset(cnt,0,sizeof(cnt));
for(int i=0;i<maxn;i++){
G[i].clear();link[i].clear();
}
}
void add_edge(int from,int to,int cost){
Edge e;
e.to = to;e.cost = cost;
G[from].push_back(e);
}
void dij(){
fill(dis,dis+maxn,inf);
dis[1] = 0;
que.push(P(0,1));
memset(pro,0,sizeof(pro));
while(!que.empty()){
P p = que.top();que.pop();
int v = p.second;
if(dis[v] != p.first) continue;
for(int i=0;i<link[v].size();i++){
int u = link[v][i];
pro[u] = max(pro[u],dis[v]);
cnt[u]--;
if(!cnt[u]){
dis[u] = max(dis[u],pro[u]);
que.push(P(dis[u],u));
}
}
for(int i=0;i<G[v].size();i++){
Edge e = G[v][i];
if(dis[e.to] > dis[v] + e.cost){
dis[e.to] = dis[v] + e.cost;
if(!cnt[e.to]) que.push(P(dis[e.to],e.to));
}
}
}
//for(int i=1;i<=n;i++) cout<<dis[i]<<endl;
printf("%d\n",dis[n]);
}
int main(){
int cas = 0;
scanf("%d",&cas);
while(cas--){
scanf("%d%d",&n,&m);
init();
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
}
for(int i=1;i<=n;i++){
scanf("%d",&cnt[i]);
int tmp;
for(int j=0;j<cnt[i];j++){
scanf("%d",&tmp);
link[tmp].push_back(i);
}
}
dij();
}
return 0;
}