我们要找一条从1到N的最短路。
现在每个点都会在一些时间关闭通道,这些时间不能在这些点上。
思路:
在SPFA过程中,更新点v的最短路时,判断一下当前时间是否处于不能通过的时间上,这里对于每个点来讲,我们都进行一次二分查找即可。
如果这个点处于可以通过时间上,那么直接更新,否则延迟即可,延迟到的时间我们预处理一下就行了。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
vector<int>mp[150000];
vector<int>nex[150000];
struct node
{
int from,to,next,w;
}e[5151111];
int n,m,cont;
int head[150000];
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
/*************************************/
int find(int v,int t)
{
int l=0;
int r=mp[v].size()-1;
while(r-l>=0)
{
int mid=(l+r)/2;
if(mp[v][mid]>t)
{
r=mid-1;
}
else if(mp[v][mid]<t)
{
l=mid+1;
}
else
{
return nex[v][mid];
}
}
return t;
}
int dist[150000];
int vis[150000];
void SPFA()
{
queue<int>s;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)dist[i]=0x3f3f3f3f;
dist[1]=find(1,0);
s.push(1);
while(!s.empty())
{
int u=s.front();
vis[u]=0;
s.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
int ttt=dist[u]+w;
if(v!=n)ttt=find(v,ttt);
if(dist[v]>ttt)
{
dist[v]=ttt;
if(vis[v]==0)
{
vis[v]=1;
s.push(v);
}
}
}
}
if(dist[n]==0x3f3f3f3f)printf("-1\n");
else printf("%d\n",dist[n]);
}
/*************************************/
int main()
{
while(~scanf("%d%d",&n,&m))
{
cont=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)mp[i].clear(),nex[i].clear();
for(int i=1;i<=m;i++)
{
int x,y,w;scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
for(int i=1;i<=n;i++)
{
int k;scanf("%d",&k);
while(k--)
{
int v;scanf("%d",&v);
mp[i].push_back(v);
}
for(int j=mp[i].size()-1;j>=0;j--)
{
int pre;
if(j==mp[i].size()-1||mp[i][j]!=mp[i][j+1]-1)
{
pre=mp[i][j]+1;
nex[i].push_back(mp[i][j]+1);
}
else nex[i].push_back(pre);
}
reverse(nex[i].begin(),nex[i].end());
}
SPFA();
}
}