算法要素:djst+次大(小)值思想
具体实现:
去学k短路然后把k设成2
djst统计最小值和次小值
但是会出现一个问题:djst的基础思想是通过vis数组保证每一个点只被修改一次。
但是由于要维护最小值和次小值,因此可能出现最小值已被更新完但是次小值根本就没有被更新的情况。
这个时候vis数组肯定是要去掉的。
此时我们可以加入一条
if(q.top().first!=dis[q.top().second]) continue;
来强行保证复杂度。
具体:大意就是一个点会被更新至最优后,它在队列中的dis却是在之前插入的,因此不必取出并用它更新其他点。
几道题:
洛谷P2865 [USACO06NOV]Roadblocks G 纯板子
洛谷P2829 大逃离 纯板子+一点小特判
洛谷P1491 集合位置 非严格次短路板子(更新时不要求严格小于即可)
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+60;
int dis[maxn],sdis[maxn];
int n,m,head[maxn],s,ecnt=-1;
struct mint
{
int nxt,v,w;
}e[maxn<<1];
inline void addline(int u,int v,int w)
{
e[++ecnt].nxt=head[u];
e[ecnt].v=v;
e[ecnt].w=w;
head[u]=ecnt;
}
void djst()
{
memset(dis,0x3f,sizeof(dis));
memset(sdis,0x3f,sizeof(sdis));
priority_queue<pair<int,int> >q;
dis[1]=0;
q.push(make_pair(0,1));
while(!q.empty())
{
int u=q.top().second;
int d=-q.top().first;
q.pop();
if(d==dis[u])
{
// printf("u=%d\n",u);
// printf("1\n");
for(int i=head[u];~i;i=e[i].nxt)
{
int v=e[i].v;
int flag=0;
if(dis[u]+e[i].w<dis[v])
{
sdis[v]=dis[v];
dis[v]=dis[u]+e[i].w;
flag=1;
q.push(make_pair(-dis[v],v));
}
if(sdis[u]+e[i].w<sdis[v])
{
sdis[v]=sdis[u]+e[i].w;
if(!flag)
{
q.push(make_pair(-dis[v],v));
flag=1;
}
}
if(dis[u]+e[i].w>dis[v] && dis[u]+e[i].w<sdis[v])
{
sdis[v]=dis[u]+e[i].w;
if(!flag)
{
q.push(make_pair(-dis[v],v));
}
}
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
addline(a,b,c);
addline(b,a,c);
}
djst();
printf("%d\n",sdis[n]);
return 0;
}