次短路
次短路
本来以为贼简单,就直接按照之前记的次短路板子打了,打完就直接......WA了。
我真是百思不得其解啊,次短路啊,没毛病啊。
最后终于想明白了
次短路有两种
- 可以重复过点的次短路
- 不可以重复过点的次短路
我们举个简单的例子。
则次短路分别为
- 1->2->1->2->3 长度为4
- 1->3 长度为5
下边,我们对两种类型都举一个例题,并讲明解决方法
可重复
本题知识点为拆点+次短路计数
由于,我们要尽量多的合法路径数,其中包括最短路以及和最短路仅差1的次短路的条数
其中并未对重复过点进行限制,并且重复过点的答案依旧是合法答案。
对于这类次短路,我们的解决方案也比较简单,就跟随着最短路,不断更新次短路即可
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,pair<int,int>> PIII;
const int N = 1010,M = 1e4 + 10,INF = 0x3f3f3f3f;
int h[N],e[M],ne[M],w[M],idx;
int dist[N][2],f[N][2];
bool st[N][2];
int n,m,s,E;
void add(int a,int b,int c)
{
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void dijkstra()
{
memset(dist,0x3f,sizeof dist);
memset(f,0,sizeof f);
memset(st,0,sizeof st);
dist[s][0]=0;
f[s][0]=1;
priority_queue<PIII,vector<PIII>,greater<PIII>> pq;
pq.push({0,{s,0}});
while(pq.size())
{
auto t = pq.top();
pq.pop();
int ver = t.second.first,type=t.second.second;
if(st[ver][type]) continue;
st[ver][type]=1;
for(int i=h[ver];~i;i=ne[i])
{
int j = e[i];
if(dist[j][0]>dist[ver][type]+w[i])
{
dist[j][1]=dist[j][0],f[j][1]=f[j][0];
pq.push({dist[j][1],{j,1}});
dist[j][0]=dist[ver][type]+w[i],f[j][0]=f[ver][type];
pq.push({dist[j][0],{j,0}});
}
else if(dist[j][0]==dist[ver][type]+w[i])
f[j][0]+=f[ver][type];
else if(dist[j][1]>dist[ver][type]+w[i])
{
dist[j][1]=dist[ver][type]+w[i];
f[j][1]=f[ver][type];
}
else if(dist[j][1]==dist[ver][type]+w[i])
f[j][1]+=f[ver][type];
}
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(h, -1, sizeof h);
idx=0;
cin>>n>>m;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
cin>>s>>E;
dijkstra();
int res = f[E][0];
if(dist[E][1]==dist[E][0]+1) res+=f[E][1];
cout<<res<<endl;
}
return 0;
}
不可重复
这就是,昨天晚上给我造成最大困扰的问题了,我原本记忆的是可以重复的类型的次短路,打完直接WA了,寄
这里举的例题是P1491 集合位置
按照题意,我们要找到的是一条和最短路不同的路径,其中和最短路至少要有一条路径不相同,且不能反复过一个点。
此时,我们的解决方案也比较简单。
先找出最短路,然后枚举最短路中的边,该条边不能走,再跑一个最短路,跑出的次短路就在这些最短路中
这里,我们用一个常见的技巧,通过pre数组将最短路记录下来
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef pair<double,int> PDI;
const int N = 210,M = N*N;
int h[N],e[M],ne[M],idx;
PII P[N];
int pre[N];
double w[M],dist[M];
bool st[N];
int n,m;
double get(int a,int b)
{
double dx = P[a].first - P[b].first,dy = P[a].second - P[b].second;
return sqrt(dx*dx+dy*dy);
}
void add(int a,int b,double c)
{
e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
}
double dijkstra(int x,int y)
{
for(int i=1;i<=n;i++) dist[i] = 1e9,st[i] = 0;
priority_queue<PDI,vector<PDI>,greater<PDI>> q;
dist[1] = 0;
q.push({0,1});
while(q.size())
{
auto t = q.top();
q.pop();
int ver = t.second;
if(st[ver]) continue;
st[ver] = 1;
for(int i=h[ver];~i;i=ne[i])
{
int j = e[i];
if((ver==x&&j==y)||(ver==y&&j==x)) continue;
if(dist[j]>dist[ver]+w[i])
{
dist[j] = dist[ver] + w[i];
if(x==-1&&y==-1) pre[j] = ver;
q.push({dist[j],j});
}
}
}
return dist[n];
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) cin>>P[i].first>>P[i].second;
while(m--)
{
int a,b;cin>>a>>b;
double c = get(a,b);
add(a,b,c),add(b,a,c);
}
dijkstra(-1,-1);
double ans = 1e9;
int x = n;
do
{
double res = dijkstra(pre[x],x);
ans = min(ans,res);
x = pre[x];
}while(x!=1);
if(ans==1e9) puts("-1");
else printf("%.2lf",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步