题意
无向图,从一个点到另一个点需要一定的时间,可以从1号节点出发放出无限个炸弹去摧毁某些点,每个节点被k个节点保护,一个点只有当保护它的点被摧毁后才能到达,求到达点n最短用时。
分析
最短路,用Dijkstra而非Spfa。
Dijkstra与Spfa的区别:Dijkstra从队列中取出的点一定是最短路已经确定的点而Spfa不一定。
对于每一个点,记录保护它的点的数量,只有当保护它的点都被摧毁且dis!=INF时将其放入队列。
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 3010
#define MAXM 70010
#define INF 100000000
int Adj[MAXN],nxt[MAXM],V[MAXM],w[MAXM],c;
void AddEdge(int u,int v,int t)
{
c++;
V[c]=v,w[c]=t;
nxt[c]=Adj[u];Adj[u]=c;
}
typedef pair<int,int> PII;
vector<int>G[MAXN];
int du[MAXN],dis[MAXN];
void Dijkstra()
{
priority_queue<PII,vector<PII>,greater<PII> > Q;
Q.push(PII(0,1));
dis[1]=0;
while(!Q.empty())
{
PII p=Q.top();Q.pop();
int u=p.second;
if(dis[u]!=p.first) continue;
int v;
for(int i=0;i<G[u].size();i++)
{
v=G[u][i];
du[v]--;
dis[v]=max(dis[v],dis[u]);
if(du[v]==0&&dis[v]!=INF)
Q.push(PII(dis[v],v));
}
for(int i=Adj[u];i;i=nxt[i])
{
v=V[i];
if(dis[v]>dis[u]+w[i])
{
dis[v]=dis[u]+w[i];
if(du[v]==0)
Q.push(PII(dis[v],v));
}
}
}
}
int main()
{
int n,m,u,v,x;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&x);
AddEdge(u,v,x);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
du[i]=x;
while(x--)
{
scanf("%d",&u);
G[u].push_back(i);
}
}
for(int i=1;i<=n;i++)
dis[i]=INF;
Dijkstra();
printf("%d\n",dis[n]);
return 0;
}