洛谷P1491集合位置

题目链接https://www.luogu.org/problemnew/show/P1491

就是求第一个点到第n个点的次短路

第一次spfa用前驱记录最短路

第二次spfa删去最短路中的一条边

记录前驱开一个pre数组,在每次松弛操作时,如果d[i]被更新就pre[i]=j;表示当前到第i个点的最短路中,j是i的前驱节点

主函数中,从第n个点开始,即i=n,不断地进行找前驱i=pre[i] 直到pre[i]=1,这个过程中的点连成路径

为什么要去掉最短路上的一条边呢?

因为次短路和最短路至少有一条边不是共有的,需要想想理解一下,,,

code


#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=208;
int n,m;
struct p{
    int x,y;
}po[maxn];
struct re{
    int t;
    double dis;
};
vector<re>g[maxn];
int pre[maxn];
double distance(int x1,int y1,int x2,int y2)
{
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void spfa1()
{
    queue<int>q;
    double d[maxn];
    bool vis[maxn];
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++) d[i]=99999999;
    d[1]=0;vis[1]=1;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<g[u].size();i++)
        {
            int t=g[u][i].t;
            double w=g[u][i].dis;
            if(d[t]>d[u]+w)
            {
                d[t]=d[u]+w;
                pre[t]=u;
                if(!vis[t]){
                    q.push(t);
                    vis[t]=1;
                }
            }
        }
    } 
}
double spfa2(int x,int y)
{
    queue<int>q;
    bool vis[maxn];
    double d[maxn];
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=n;i++) d[i]=99999999;
    d[1]=0;vis[1]=1;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=0;i<g[u].size();i++)
        {
            int t=g[u][i].t;
            double w=g[u][i].dis;
            if((u==x&&t==y)||(u==y&&t==x)) continue;
            if(d[t]>d[u]+w)
            {
                d[t]=d[u]+w;
                if(!vis[t]){
                    q.push(t);
                    vis[t]=1;
                }
            }
        }
    }
    return d[n];
}
int main()
{
    int pj,qj;
    double dis;
    double ans=99999999;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&po[i].x,&po[i].y);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&pj,&qj);
        dis=distance(po[pj].x,po[pj].y,po[qj].x,po[qj].y);
        g[pj].push_back((re){qj,dis});
        g[qj].push_back((re){pj,dis});
    }
    memset(pre,0,sizeof(pre));
    spfa1();
    int now=n;
    while(pre[now]!=1){
    	double sxy=spfa2(now,pre[now]);
    	if(ans>sxy) ans=sxy;
    	now=pre[now];
    }
    double sxy=spfa2(now,1);
    if(ans>sxy) ans=sxy;
    if(ans==99999999) printf("-1");
    else printf("%.2f",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值