冷静 清醒|

艾特玖

园龄:3年11个月粉丝:12关注:7

次短路

次短路

本来以为贼简单,就直接按照之前记的次短路板子打了,打完就直接......WA了。

我真是百思不得其解啊,次短路啊,没毛病啊。

最后终于想明白了

次短路有两种

  1. 可以重复过点的次短路
  2. 不可以重复过点的次短路

我们举个简单的例子。

则次短路分别为

  1. 1->2->1->2->3 长度为4
  2. 1->3 长度为5

下边,我们对两种类型都举一个例题,并讲明解决方法

可重复

AcWing383观光

本题知识点为拆点+次短路计数

由于,我们要尽量多的合法路径数,其中包括最短路以及和最短路仅差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;
}

本文作者:艾特玖

本文链接:https://www.cnblogs.com/aitejiu/p/16048839.html

版权声明:本作品采用艾特玖许可协议进行许可。

posted @   艾特玖  阅读(69)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起