#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f//可以使用memset
//链式前向星+SPFA
struct edge{
int next;//下一条边的存储下标(默认0
int to;//这条边终点
int lenth;//权值
}a[400020];//结构体数组edge存边,edge[i]表示第i条边
int head[200020];// head[i]存以i为起点的最后一条边的编号
int n,m,q, nn;
int vis[200020];
struct nodope{
int val; //val花费 d结束时的颜色
set<int> d;
}d[200020]; //当前点
int spfa()
{
memset(vis,0,sizeof vis);
vis[1] = 1;
queue<int> q;
q.push(1);
for(int i=0;i<=n;i++)
{
d[i].val=INF,
d[i].d.clear();
}
d[1].val=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=a[i].next)//遍历以u为起点的点
{
int to = a[i].to;
if(d[to].val>(d[u].val+(d[u].d.find(a[i].lenth)==d[u].d.end())))
{
d[to].val = d[u].val+(d[u].d.find(a[i].lenth)==d[u].d.end());
d[to].d.clear();
d[to].d.insert(a[i].lenth);
if(!vis[to])
{
q.push(to);
vis[to] = 1;
}
}
else if(d[to].val==(d[u].val+(d[u].d.find(a[i].lenth)==d[u].d.end()))&&d[to].d.find(a[i].lenth)==d[to].d.end())
{
d[to].d.insert(a[i].lenth);
if(!vis[to])
{
q.push(to);
vis[to] = 1;
}
}
}
}
if(d[n].val != INF)
printf("%d\n",d[n].val);
else
printf("-1\n");
return 0;
}
void add(int x,int y,int z)
{
//nn即cnt 为边的计数 从0开始计
a[nn].lenth=z;//终点
a[nn].to=y;//权值
a[nn].next=head[x];//以x为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
head[x]=nn++;//更新以x为起点的上一条边的编号
//若以点i为起点的边新增了一条,在edge中的下标为j.
//那么edge[j].next=head[i];然后head[i]=j.
//即每次新加的边作为第一条边,最后倒序遍历
/*题设是双向边*/
a[nn].lenth=z;
a[nn].to=x;
a[nn].next=head[y];
head[y]=nn++;
}
int main()
{
//freopen("2.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
for(int i = 0;i <= n;i++)
head[i] = -1;//head初始化-1
nn = 0;//cnt
for(int i = 0;i < m;i++)
{
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
add(x, y, z);
}
spfa();
}
return 0;
}
SPFA 模板来自上?原博
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int M=10005;
struct A{
int y,time,next;
}a[M<<1];
int pre[M],cent=0;//链式前向星数组
int vis[M],ven[M],nums[M];
//SPFS数组,vis记录最短路,ven记录是否在队列,nums记录入队次数
void add(int x,int y,int k)//链式前向星,加入节点
{
a[cent].y=y, a[cent].time=k, a[cent].next=pre[x];
pre[x]=cent++;
}
bool SPFA(int s,int n)
{
queue <int> q;
memset(vis,inf,sizeof(vis));
memset(ven,0,sizeof(ven));
memset(nums,0,sizeof(nums));
vis[s]=0;//初始化距离
ven[s]=1,nums[s]++;//标记s节点在队列,队列次数+1
q.push(s);
while(!q.empty())
{
int x=q.front();
q.pop();//出队
ven[x]=0;//标记不在队列
for(int i=pre[x]; ~i; i=a[i].next)//遍历与x节点连通的点
{
int y=a[i].y;
if(vis[y]>vis[x]+a[i].time)//更新
{
vis[y]=vis[x]+a[i].time;
if(!ven[y])
//由于更新了节点,所以后续以这个为基础的最短路,也要更新下
//所以如果在队列就不用加入,不在的话加入更新后续节点
{
q.push(y);
ven[y]=1;//标记这个节点在队列中
nums[y]++;//记录加入次数
if(nums[y]>n)//如果这个点加入超过n次,说明存在负圈,直接返回
return false;
}
}
}
}
return true;
}
int main()
{
int n,m,t;
int b[M],c[M];
while(cin>>n>>m>>t)
{
cent=0;
memset(pre,-1,sizeof(pre));
for(int i=0;i<n;i++)
{
int x,y,k;
cin>>x>>y>>k;
add(x,y,k);
add(y,x,k);
}
for(int i=0;i<m;i++)
{
cin>>b[i];
}
for(int i=0;i<t;i++)
{
cin>>c[i];
}
int minn=inf;
for(int i=0;i<m;i++)//遍历多个找寻最小
{
SPFA(b[i],n);
for(int j=0;j<t;j++)
minn=min(minn,vis[c[j]]);
}
cout<<minn<<endl;
}
}